# HG changeset patch # User duke # Date 1499287321 -7200 # Node ID 1c9922f121ffbc6f1c378f6350936056dde0d5d7 # Parent 047a57b0839af83954556c9f80a7c3c3bbd30cd0# Parent dca22f52244924fe2b646fa8fb6bd8020c93d9ad Merge diff -r 047a57b0839a -r 1c9922f121ff .hgtags-top-repo --- a/.hgtags-top-repo Tue Jan 17 07:41:04 2017 +0100 +++ b/.hgtags-top-repo Wed Jul 05 22:42:01 2017 +0200 @@ -394,3 +394,4 @@ b119012d1c2ab2570fe8718633840d0c1f1f441d jdk-9+149 6234069ff9789f7582e1faa32cb6283cbd1a5a2d jdk-9+150 71a766d4c18041a7f833ee22823125b02e1a7f1e jdk-9+151 +ef056360ddf3977d7d2ddbeb456a4d612d19ea05 jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/basics.m4 --- a/common/autoconf/basics.m4 Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/basics.m4 Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1011,6 +1011,8 @@ # Test which kind of tar was found if test "x$($TAR --version | $GREP "GNU tar")" != "x"; then TAR_TYPE="gnu" + elif test "x$($TAR --version | $GREP "bsdtar")" != "x"; then + TAR_TYPE="bsd" elif test "x$($TAR -v | $GREP "bsdtar")" != "x"; then TAR_TYPE="bsd" elif test "x$OPENJDK_BUILD_OS" = "xsolaris"; then @@ -1038,12 +1040,36 @@ AC_SUBST(TAR_SUPPORTS_TRANSFORM) ]) +AC_DEFUN([BASIC_CHECK_GREP], +[ + # Test that grep supports -Fx with a list of pattern which includes null pattern. + # This is a problem for the grep resident on AIX. + AC_MSG_CHECKING([that grep ($GREP) -Fx handles empty lines in the pattern list correctly]) + # Multiple subsequent spaces.. + STACK_SPACES='aaa bbb ccc' + # ..converted to subsequent newlines, causes STACK_LIST to be a list with some empty + # patterns in it. + STACK_LIST=${STACK_SPACES// /$'\n'} + NEEDLE_SPACES='ccc bbb aaa' + NEEDLE_LIST=${NEEDLE_SPACES// /$'\n'} + RESULT="$($GREP -Fvx "$STACK_LIST" <<< "$NEEDLE_LIST")" + if test "x$RESULT" == "x"; then + AC_MSG_RESULT([yes]) + else + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + ADDINFO="Please make sure you use GNU grep, usually found at /opt/freeware/bin." + fi + AC_MSG_ERROR([grep does not handle -Fx correctly. ${ADDINFO}]) + fi +]) + AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS], [ BASIC_CHECK_GNU_MAKE BASIC_CHECK_FIND_DELETE BASIC_CHECK_TAR + BASIC_CHECK_GREP # These tools might not be installed by default, # need hint on how to install them. diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/buildjdk-spec.gmk.in --- a/common/autoconf/buildjdk-spec.gmk.in Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/buildjdk-spec.gmk.in Wed Jul 05 22:42:01 2017 +0200 @@ -68,7 +68,6 @@ CFLAGS_JDKEXE := @OPENJDK_BUILD_CFLAGS_JDKEXE@ CXXFLAGS_JDKEXE := @OPENJDK_BUILD_CXXFLAGS_JDKEXE@ LDFLAGS_JDKEXE := @OPENJDK_BUILD_LDFLAGS_JDKEXE@ -OPENJDK_TARGET_CPU_JLI_CFLAGS := @OPENJDK_BUILD_CPU_JLI_CFLAGS@ JVM_CFLAGS := @OPENJDK_BUILD_JVM_CFLAGS@ JVM_LDFLAGS := @OPENJDK_BUILD_JVM_LDFLAGS@ diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/flags.m4 --- a/common/autoconf/flags.m4 Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/flags.m4 Wed Jul 05 22:42:01 2017 +0200 @@ -815,11 +815,6 @@ $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} -D__solaris__" fi - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - $2CFLAGS_JDK="${$2CFLAGS_JDK} -D__solaris__" - $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} -D__solaris__" - fi - $2CFLAGS_JDK="${$2CFLAGS_JDK} ${$2EXTRA_CFLAGS}" $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} ${$2EXTRA_CXXFLAGS}" $2LDFLAGS_JDK="${$2LDFLAGS_JDK} ${$2EXTRA_LDFLAGS}" diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/generated-configure.sh Wed Jul 05 22:42:01 2017 +0200 @@ -3564,7 +3564,7 @@ # Include these first... # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -3731,6 +3731,8 @@ + + # Check if build directory is on local disk. If not possible to determine, # we prefer to claim it's local. # Argument 1: directory to test @@ -4122,7 +4124,7 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4237,6 +4239,17 @@ esac } +brew_help() { + case $1 in + openjdk) + PKGHANDLER_COMMAND="brew cask install java" ;; + freetype) + PKGHANDLER_COMMAND="brew install freetype" ;; + ccache) + PKGHANDLER_COMMAND="brew install ccache" ;; + esac +} + port_help() { PKGHANDLER_COMMAND="" } @@ -4362,7 +4375,7 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4667,7 +4680,7 @@ # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -5167,7 +5180,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1483542685 +DATE_WHEN_GENERATED=1484571183 ############################################################################### # @@ -17544,7 +17557,7 @@ # Must be done before we can call HELP_MSG_MISSING_DEPENDENCY. - for ac_prog in apt-get yum port pkgutil pkgadd + for ac_prog in apt-get yum brew port pkgutil pkgadd do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -21209,6 +21222,8 @@ # Test which kind of tar was found if test "x$($TAR --version | $GREP "GNU tar")" != "x"; then TAR_TYPE="gnu" + elif test "x$($TAR --version | $GREP "bsdtar")" != "x"; then + TAR_TYPE="bsd" elif test "x$($TAR -v | $GREP "bsdtar")" != "x"; then TAR_TYPE="bsd" elif test "x$OPENJDK_BUILD_OS" = "xsolaris"; then @@ -21238,6 +21253,29 @@ + # Test that grep supports -Fx with a list of pattern which includes null pattern. + # This is a problem for the grep resident on AIX. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking that grep ($GREP) -Fx handles empty lines in the pattern list correctly" >&5 +$as_echo_n "checking that grep ($GREP) -Fx handles empty lines in the pattern list correctly... " >&6; } + # Multiple subsequent spaces.. + STACK_SPACES='aaa bbb ccc' + # ..converted to subsequent newlines, causes STACK_LIST to be a list with some empty + # patterns in it. + STACK_LIST=${STACK_SPACES// /$'\n'} + NEEDLE_SPACES='ccc bbb aaa' + NEEDLE_LIST=${NEEDLE_SPACES// /$'\n'} + RESULT="$($GREP -Fvx "$STACK_LIST" <<< "$NEEDLE_LIST")" + if test "x$RESULT" == "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + ADDINFO="Please make sure you use GNU grep, usually found at /opt/freeware/bin." + fi + as_fn_error $? "grep does not handle -Fx correctly. ${ADDINFO}" "$LINENO" 5 + fi + + # These tools might not be installed by default, # need hint on how to install them. @@ -24359,15 +24397,13 @@ fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5 +$as_echo_n "checking if packaged modules are kept... " >&6; } if test "x$enable_keep_packaged_modules" = "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5 -$as_echo_n "checking if packaged modules are kept... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } JLINK_KEEP_PACKAGED_MODULES=true elif test "x$enable_keep_packaged_modules" = "xno"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5 -$as_echo_n "checking if packaged modules are kept... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } JLINK_KEEP_PACKAGED_MODULES=false @@ -24376,6 +24412,8 @@ $as_echo "yes (default)" >&6; } JLINK_KEEP_PACKAGED_MODULES=true else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: error" >&5 +$as_echo "error" >&6; } as_fn_error $? "--enable-keep-packaged-modules accepts no argument" "$LINENO" 5 fi @@ -29942,6 +29980,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -33235,6 +33275,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -34534,6 +34576,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -48601,6 +48645,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -48762,6 +48808,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -49897,11 +49945,6 @@ CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__" fi - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - CFLAGS_JDK="${CFLAGS_JDK} -D__solaris__" - CXXFLAGS_JDK="${CXXFLAGS_JDK} -D__solaris__" - fi - CFLAGS_JDK="${CFLAGS_JDK} ${EXTRA_CFLAGS}" CXXFLAGS_JDK="${CXXFLAGS_JDK} ${EXTRA_CXXFLAGS}" LDFLAGS_JDK="${LDFLAGS_JDK} ${EXTRA_LDFLAGS}" @@ -50720,11 +50763,6 @@ OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} -D__solaris__" fi - if test "x$OPENJDK_TARGET_OS" = xsolaris; then - OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -D__solaris__" - OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} -D__solaris__" - fi - OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} ${OPENJDK_BUILD_EXTRA_CFLAGS}" OPENJDK_BUILD_CXXFLAGS_JDK="${OPENJDK_BUILD_CXXFLAGS_JDK} ${OPENJDK_BUILD_EXTRA_CXXFLAGS}" OPENJDK_BUILD_LDFLAGS_JDK="${OPENJDK_BUILD_LDFLAGS_JDK} ${OPENJDK_BUILD_EXTRA_LDFLAGS}" @@ -52844,6 +52882,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -56649,6 +56689,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -56721,6 +56763,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -56864,6 +56908,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -60741,6 +60787,345 @@ fi fi + if test "x$FOUND_FREETYPE" != xyes; then + FREETYPE_BASE_DIR="$SYSROOT/usr/local" + + POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" + POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" + METHOD="well-known location" + + # Let's start with an optimistic view of the world :-) + FOUND_FREETYPE=yes + + # First look for the canonical freetype main include file ft2build.h. + if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then + # Oh no! Let's try in the freetype2 directory. This is needed at least at Mac OS X Yosemite. + POTENTIAL_FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH/freetype2" + if ! test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then + # Fail. + FOUND_FREETYPE=no + fi + fi + + if test "x$FOUND_FREETYPE" = xyes; then + # Include file found, let's continue the sanity check. + { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5 +$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;} + + # Reset to default value + FREETYPE_BASE_NAME=freetype + FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}" + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then + if test "x$OPENJDK_TARGET_OS" = xmacosx \ + && test -s "$POTENTIAL_FREETYPE_LIB_PATH/${LIBRARY_PREFIX}freetype.6${SHARED_LIBRARY_SUFFIX}"; then + # On Mac OS X Yosemite, the symlink from libfreetype.dylib to libfreetype.6.dylib disappeared. Check + # for the .6 version explicitly. + FREETYPE_BASE_NAME=freetype.6 + FREETYPE_LIB_NAME="${LIBRARY_PREFIX}${FREETYPE_BASE_NAME}${SHARED_LIBRARY_SUFFIX}" + { $as_echo "$as_me:${as_lineno-$LINENO}: Compensating for missing symlink by using version 6 explicitly" >&5 +$as_echo "$as_me: Compensating for missing symlink by using version 6 explicitly" >&6;} + else + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;} + FOUND_FREETYPE=no + fi + else + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # On Windows, we will need both .lib and .dll file. + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/${FREETYPE_BASE_NAME}.lib. Ignoring location." >&6;} + FOUND_FREETYPE=no + fi + elif test "x$OPENJDK_TARGET_OS" = xsolaris \ + && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then + # Found lib in isa dir, use that instead. + POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&5 +$as_echo "$as_me: Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead" >&6;} + fi + fi + fi + + if test "x$FOUND_FREETYPE" = xyes; then + + # Only process if variable expands to non-empty + + if test "x$POTENTIAL_FREETYPE_INCLUDE_PATH" != x; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-style (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a unix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + if test -d "$path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`" + else + dir="`$DIRNAME "$path"`" + base="`$BASENAME "$path"`" + POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$dir"; $THEPWDCMD -L`/$base" + fi + fi + fi + + + # Only process if variable expands to non-empty + + if test "x$POTENTIAL_FREETYPE_LIB_PATH" != x; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_LIB_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-style (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a unix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + if test -d "$path"; then + POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`" + else + dir="`$DIRNAME "$path"`" + base="`$BASENAME "$path"`" + POTENTIAL_FREETYPE_LIB_PATH="`cd "$dir"; $THEPWDCMD -L`/$base" + fi + fi + fi + + + FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5 +$as_echo_n "checking for freetype includes... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5 +$as_echo "$FREETYPE_INCLUDE_PATH" >&6; } + FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5 +$as_echo_n "checking for freetype libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5 +$as_echo "$FREETYPE_LIB_PATH" >&6; } + fi + + fi if test "x$OPENJDK_TARGET_OS" = xmacosx; then if test "x$FOUND_FREETYPE" != xyes; then @@ -62122,6 +62507,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -62477,6 +62864,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -62682,6 +63071,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -62870,6 +63261,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -62949,6 +63342,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -64058,6 +64453,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -64142,6 +64539,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/help.m4 --- a/common/autoconf/help.m4 Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/help.m4 Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # 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 @@ AC_DEFUN_ONCE([HELP_SETUP_DEPENDENCY_HELP], [ - AC_CHECK_PROGS(PKGHANDLER, apt-get yum port pkgutil pkgadd) + AC_CHECK_PROGS(PKGHANDLER, apt-get yum brew port pkgutil pkgadd) ]) AC_DEFUN([HELP_MSG_MISSING_DEPENDENCY], @@ -46,6 +46,8 @@ apt_help $MISSING_DEPENDENCY ;; yum) yum_help $MISSING_DEPENDENCY ;; + brew) + brew_help $MISSING_DEPENDENCY ;; port) port_help $MISSING_DEPENDENCY ;; pkgutil) @@ -147,6 +149,17 @@ esac } +brew_help() { + case $1 in + openjdk) + PKGHANDLER_COMMAND="brew cask install java" ;; + freetype) + PKGHANDLER_COMMAND="brew install freetype" ;; + ccache) + PKGHANDLER_COMMAND="brew install ccache" ;; + esac +} + port_help() { PKGHANDLER_COMMAND="" } diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/jdk-options.m4 --- a/common/autoconf/jdk-options.m4 Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/jdk-options.m4 Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -382,18 +382,18 @@ AC_ARG_ENABLE([keep-packaged-modules], [AS_HELP_STRING([--disable-keep-packaged-modules], [Do not keep packaged modules in jdk image @<:@enable@:>@])]) + AC_MSG_CHECKING([if packaged modules are kept]) if test "x$enable_keep_packaged_modules" = "xyes"; then - AC_MSG_CHECKING([if packaged modules are kept]) AC_MSG_RESULT([yes]) JLINK_KEEP_PACKAGED_MODULES=true elif test "x$enable_keep_packaged_modules" = "xno"; then - AC_MSG_CHECKING([if packaged modules are kept]) AC_MSG_RESULT([no]) JLINK_KEEP_PACKAGED_MODULES=false elif test "x$enable_keep_packaged_modules" = "x"; then AC_MSG_RESULT([yes (default)]) JLINK_KEEP_PACKAGED_MODULES=true else + AC_MSG_RESULT([error]) AC_MSG_ERROR([--enable-keep-packaged-modules accepts no argument]) fi diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/lib-freetype.m4 --- a/common/autoconf/lib-freetype.m4 Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/lib-freetype.m4 Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -348,6 +348,10 @@ FREETYPE_BASE_DIR="$SYSROOT/usr/X11" LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) fi + if test "x$FOUND_FREETYPE" != xyes; then + FREETYPE_BASE_DIR="$SYSROOT/usr/local" + LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) + fi if test "x$OPENJDK_TARGET_OS" = xmacosx; then if test "x$FOUND_FREETYPE" != xyes; then diff -r 047a57b0839a -r 1c9922f121ff common/autoconf/spec.gmk.in --- a/common/autoconf/spec.gmk.in Tue Jan 17 07:41:04 2017 +0100 +++ b/common/autoconf/spec.gmk.in Wed Jul 05 22:42:01 2017 +0200 @@ -274,8 +274,6 @@ CONFIGURESUPPORT_OUTPUTDIR:=@CONFIGURESUPPORT_OUTPUTDIR@ BUILDJDK_OUTPUTDIR=$(BUILD_OUTPUT)/buildjdk -BUILD_HOTSPOT=@BUILD_HOTSPOT@ - BUILD_FAILURE_HANDLER := @BUILD_FAILURE_HANDLER@ ENABLE_GENERATE_CLASSLIST := @ENABLE_GENERATE_CLASSLIST@ @@ -642,7 +640,6 @@ NICE:=@NICE@ PATCH:=@PATCH@ PRINTF:=@PRINTF@ -PWD:=@THEPWDCMD@ RM:=@RM@ RMDIR:=@RMDIR@ SED:=@SED@ @@ -778,11 +775,18 @@ # Images directory definitions JDK_IMAGE_SUBDIR:=jdk JRE_IMAGE_SUBDIR:=jre +JRE_COMPACT1_IMAGE_SUBDIR := jre-compact1 +JRE_COMPACT2_IMAGE_SUBDIR := jre-compact2 +JRE_COMPACT3_IMAGE_SUBDIR := jre-compact3 # Colon left out to be able to override output dir for bootcycle-images JDK_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(JDK_IMAGE_SUBDIR) JRE_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(JRE_IMAGE_SUBDIR) +JRE_COMPACT1_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(JRE_COMPACT1_IMAGE_SUBDIR) +JRE_COMPACT2_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(JRE_COMPACT2_IMAGE_SUBDIR) +JRE_COMPACT3_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(JRE_COMPACT3_IMAGE_SUBDIR) + # Test image, as above TEST_IMAGE_SUBDIR:=test TEST_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(TEST_IMAGE_SUBDIR) @@ -818,6 +822,12 @@ endif JDK_BUNDLE_NAME := jdk-$(BASE_NAME)_bin$(DEBUG_PART).tar.gz JRE_BUNDLE_NAME := jre-$(BASE_NAME)_bin$(DEBUG_PART).tar.gz +JRE_COMPACT1_BUNDLE_NAME := \ + jre-$(VERSION_SHORT)+$(VERSION_BUILD)-compact1_$(OPENJDK_TARGET_BUNDLE_PLATFORM)_bin$(DEBUG_PART).tar.gz +JRE_COMPACT2_BUNDLE_NAME := \ + jre-$(VERSION_SHORT)+$(VERSION_BUILD)-compact2_$(OPENJDK_TARGET_BUNDLE_PLATFORM)_bin$(DEBUG_PART).tar.gz +JRE_COMPACT3_BUNDLE_NAME := \ + jre-$(VERSION_SHORT)+$(VERSION_BUILD)-compact3_$(OPENJDK_TARGET_BUNDLE_PLATFORM)_bin$(DEBUG_PART).tar.gz JDK_SYMBOLS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin$(DEBUG_PART)-symbols.tar.gz JRE_SYMBOLS_BUNDLE_NAME := jre-$(BASE_NAME)_bin$(DEBUG_PART)-symbols.tar.gz ifeq ($(OPENJDK_TARGET_OS), windows) diff -r 047a57b0839a -r 1c9922f121ff common/conf/jib-profiles.js --- a/common/conf/jib-profiles.js Tue Jan 17 07:41:04 2017 +0100 +++ b/common/conf/jib-profiles.js Wed Jul 05 22:42:01 2017 +0200 @@ -501,7 +501,7 @@ // extra default target. var openOnlyProfilesExtra = { "linux-x86-open": { - default_make_targets: "profiles", + default_make_targets: "profiles-bundles", configure_args: "--with-jvm-variants=client,server" } }; @@ -587,6 +587,7 @@ ], work_dir: input.get("src.full", "install_path") + "/test", environment: { + "JT_JAVA": common.boot_jdk_home, "PRODUCT_HOME": input.get(testedProfile + ".jdk", "home_path"), "TEST_IMAGE_DIR": input.get(testedProfile + ".test", "home_path"), "TEST_OUTPUT_DIR": input.src_top_dir @@ -710,10 +711,15 @@ local: "bundles/\\(jdk.*bin.tar.gz\\)", remote: "bundles/openjdk/GPL/profile/linux-x86/\\1", }, + jdk_symbols: { + local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)", + remote: "bundles/openjdk/GPL/profile/linux-x86/\\1", + }, jre: { - local: "bundles/\\(jre.*[0-9]_linux-x86_bin.tar.gz\\)", + // This regexp needs to not match the compact* files below + local: "bundles/\\(jre.*[+][0-9]\\{1,\\}_linux-x86_bin.tar.gz\\)", remote: "bundles/openjdk/GPL/profile/linux-x86/\\1", - },/* The build does not create these + }, jre_compact1: { local: "bundles/\\(jre.*-compact1_linux-x86_bin.tar.gz\\)", remote: "bundles/openjdk/GPL/profile/linux-x86/\\1", @@ -725,7 +731,7 @@ jre_compact3: { local: "bundles/\\(jre.*-compact3_linux-x86_bin.tar.gz\\)", remote: "bundles/openjdk/GPL/profile/linux-x86/\\1", - },*/ + }, } }, @@ -864,7 +870,7 @@ jtreg: { server: "javare", revision: "4.2", - build_number: "b04", + build_number: "b05", checksum_file: "MD5_VALUES", file: "jtreg_bin-4.2.zip", environment_name: "JT_HOME", diff -r 047a57b0839a -r 1c9922f121ff corba/.hgtags --- a/corba/.hgtags Tue Jan 17 07:41:04 2017 +0100 +++ b/corba/.hgtags Wed Jul 05 22:42:01 2017 +0200 @@ -394,3 +394,4 @@ 00b19338e505690abe93d5995ed74a473d969c2c jdk-9+149 9205e980062a5c4530b51021c6e274025f4ccbdf jdk-9+150 77f827f5bbad3ef795664bc675f72d98d156b9f8 jdk-9+151 +ff8cb43c07c069b1debdee44cb88ca22db1ec757 jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff hotspot/.hgtags --- a/hotspot/.hgtags Tue Jan 17 07:41:04 2017 +0100 +++ b/hotspot/.hgtags Wed Jul 05 22:42:01 2017 +0200 @@ -554,3 +554,4 @@ 30e1996bd55da36183434f24ed964adebf9ca71e jdk-9+149 98fe046473c90204cbc9b34c512b9fc10dfb8479 jdk-9+150 2a2ac7d9f52c8cb2b80077e515b5840b947e640c jdk-9+151 +31f1d26c60df7b2e516a4f84160d76ba017d4e09 jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff jaxp/.hgtags --- a/jaxp/.hgtags Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/.hgtags Wed Jul 05 22:42:01 2017 +0200 @@ -394,3 +394,4 @@ 5978df8bfa3894f2b3d07b7256f25f78dffb1f9c jdk-9+149 f85154af719f99a3b4d81b67a8b4c18a650d10f9 jdk-9+150 13c6906bfc861d99dc35a19c80b7a99f0b0ac58d jdk-9+151 +7e3da313b1746578da648155e37dd8526e83153d jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/DOM2SAX.java --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/DOM2SAX.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/DOM2SAX.java Wed Jul 05 22:42:01 2017 +0200 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,20 +17,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: DOM2SAX.java,v 1.2.4.1 2005/09/06 11:52:46 pvedula Exp $ - */ - package com.sun.org.apache.xalan.internal.xsltc.trax; import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl; import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Stack; -import java.util.Vector; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.ContentHandler; @@ -58,7 +54,7 @@ private ContentHandler _sax = null; private LexicalHandler _lex = null; private SAXImpl _saxImpl = null; - private Map _nsPrefixes = new HashMap<>(); + private Map> _nsPrefixes = new HashMap<>(); public DOM2SAX(Node root) { _dom = root; @@ -73,7 +69,7 @@ { _sax = handler; if (handler instanceof LexicalHandler) { - _lex = (LexicalHandler) handler; + _lex = (LexicalHandler)handler; } if (handler instanceof SAXImpl) { @@ -90,25 +86,22 @@ throws SAXException { boolean pushed = true; - Stack uriStack = _nsPrefixes.get(prefix); + Stack uriStack = _nsPrefixes.get(prefix); if (uriStack != null) { if (uriStack.isEmpty()) { _sax.startPrefixMapping(prefix, uri); uriStack.push(uri); - } - else { - final String lastUri = (String) uriStack.peek(); + } else { + final String lastUri = uriStack.peek(); if (!lastUri.equals(uri)) { _sax.startPrefixMapping(prefix, uri); uriStack.push(uri); - } - else { + } else { pushed = false; } } - } - else { + } else { _sax.startPrefixMapping(prefix, uri); _nsPrefixes.put(prefix, uriStack = new Stack()); uriStack.push(uri); @@ -123,7 +116,7 @@ private void endPrefixMapping(String prefix) throws SAXException { - final Stack uriStack = _nsPrefixes.get(prefix); + final Stack uriStack = _nsPrefixes.get(prefix); if (uriStack != null) { _sax.endPrefixMapping(prefix); @@ -131,22 +124,6 @@ } } - /** - * If the DOM was created using a DOM 1.0 API, the local name may be - * null. If so, get the local name from the qualified name before - * generating the SAX event. - */ - private static String getLocalName(Node node) { - final String localName = node.getLocalName(); - - if (localName == null) { - final String qname = node.getNodeName(); - final int col = qname.lastIndexOf(':'); - return (col > 0) ? qname.substring(col + 1) : qname; - } - return localName; - } - public void parse(InputSource unused) throws IOException, SAXException { parse(_dom); } @@ -173,8 +150,8 @@ * declarations. */ private void parse(Node node) throws IOException, SAXException { - Node first = null; - if (node == null) return; + if (node == null) + return; switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE @@ -198,7 +175,6 @@ _sax.characters(cdata.toCharArray(), 0, cdata.length()); } break; - case Node.COMMENT_NODE: // should be handled!!! if (_lex != null) { final String value = node.getNodeValue(); @@ -216,10 +192,9 @@ } _sax.endDocument(); break; - case Node.ELEMENT_NODE: String prefix; - Vector pushedPrefixes = new Vector(); + ArrayList pushedPrefixes = new ArrayList<>(); final AttributesImpl attrs = new AttributesImpl(); final NamedNodeMap map = node.getAttributes(); final int length = map.getLength(); @@ -235,7 +210,7 @@ final int colon = qnameAttr.lastIndexOf(':'); prefix = (colon > 0) ? qnameAttr.substring(colon + 1) : EMPTYSTRING; if (startPrefixMapping(prefix, uriAttr)) { - pushedPrefixes.addElement(prefix); + pushedPrefixes.add(prefix); } } } @@ -248,27 +223,25 @@ // Ignore NS declarations here if (!qnameAttr.startsWith(XMLNS_PREFIX)) { final String uriAttr = attr.getNamespaceURI(); - final String localNameAttr = getLocalName(attr); // Uri may be implicitly declared if (uriAttr != null) { final int colon = qnameAttr.lastIndexOf(':'); if (colon > 0) { prefix = qnameAttr.substring(0, colon); - } - else { + } else { // If no prefix for this attr, we need to create // one because we cannot use the default ns prefix = BasisLibrary.generatePrefix(); qnameAttr = prefix + ':' + qnameAttr; } if (startPrefixMapping(prefix, uriAttr)) { - pushedPrefixes.addElement(prefix); + pushedPrefixes.add(prefix); } } // Add attribute to list - attrs.addAttribute(attr.getNamespaceURI(), getLocalName(attr), + attrs.addAttribute(attr.getNamespaceURI(), attr.getLocalName(), qnameAttr, "CDATA", attr.getNodeValue()); } } @@ -276,22 +249,21 @@ // Now process the element itself final String qname = node.getNodeName(); final String uri = node.getNamespaceURI(); - final String localName = getLocalName(node); + final String localName = node.getLocalName(); - // Uri may be implicitly declared + // URI may be implicitly declared if (uri != null) { final int colon = qname.lastIndexOf(':'); prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING; if (startPrefixMapping(prefix, uri)) { - pushedPrefixes.addElement(prefix); + pushedPrefixes.add(prefix); } } // Generate SAX event to start element if (_saxImpl != null) { _saxImpl.startElement(uri, localName, qname, attrs, node); - } - else { + } else { _sax.startElement(uri, localName, qname, attrs); } @@ -308,15 +280,13 @@ // Generate endPrefixMapping() for all pushed prefixes final int nPushedPrefixes = pushedPrefixes.size(); for (int i = 0; i < nPushedPrefixes; i++) { - endPrefixMapping((String) pushedPrefixes.elementAt(i)); + endPrefixMapping(pushedPrefixes.get(i)); } break; - case Node.PROCESSING_INSTRUCTION_NODE: _sax.processingInstruction(node.getNodeName(), node.getNodeValue()); break; - case Node.TEXT_NODE: final String data = node.getNodeValue(); _sax.characters(data.toCharArray(), 0, data.length()); @@ -449,36 +419,4 @@ public String getSystemId() { return null; } - - // Debugging - private String getNodeTypeFromCode(short code) { - String retval = null; - switch (code) { - case Node.ATTRIBUTE_NODE : - retval = "ATTRIBUTE_NODE"; break; - case Node.CDATA_SECTION_NODE : - retval = "CDATA_SECTION_NODE"; break; - case Node.COMMENT_NODE : - retval = "COMMENT_NODE"; break; - case Node.DOCUMENT_FRAGMENT_NODE : - retval = "DOCUMENT_FRAGMENT_NODE"; break; - case Node.DOCUMENT_NODE : - retval = "DOCUMENT_NODE"; break; - case Node.DOCUMENT_TYPE_NODE : - retval = "DOCUMENT_TYPE_NODE"; break; - case Node.ELEMENT_NODE : - retval = "ELEMENT_NODE"; break; - case Node.ENTITY_NODE : - retval = "ENTITY_NODE"; break; - case Node.ENTITY_REFERENCE_NODE : - retval = "ENTITY_REFERENCE_NODE"; break; - case Node.NOTATION_NODE : - retval = "NOTATION_NODE"; break; - case Node.PROCESSING_INSTRUCTION_NODE : - retval = "PROCESSING_INSTRUCTION_NODE"; break; - case Node.TEXT_NODE: - retval = "TEXT_NODE"; break; - } - return retval; - } } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM.java --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM.java Wed Jul 05 22:42:01 2017 +0200 @@ -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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,14 +17,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SAX2DTM.java,v 1.2.4.1 2005/09/15 08:15:11 suresh_emailid Exp $ - */ + package com.sun.org.apache.xml.internal.dtm.ref.sax2dtm; - -import com.sun.org.apache.xml.internal.dtm.*; -import com.sun.org.apache.xml.internal.dtm.ref.*; +import com.sun.org.apache.xml.internal.dtm.DTM; +import com.sun.org.apache.xml.internal.dtm.DTMManager; +import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; +import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBaseIterators; +import com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault; +import com.sun.org.apache.xml.internal.dtm.ref.DTMStringPool; +import com.sun.org.apache.xml.internal.dtm.ref.DTMTreeWalker; +import com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource; +import com.sun.org.apache.xml.internal.dtm.ref.NodeLocator; import com.sun.org.apache.xml.internal.res.XMLErrorResources; import com.sun.org.apache.xml.internal.res.XMLMessages; import com.sun.org.apache.xml.internal.utils.FastStringBuffer; @@ -36,13 +40,23 @@ import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException; import com.sun.org.apache.xml.internal.utils.XMLString; import com.sun.org.apache.xml.internal.utils.XMLStringFactory; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Vector; import javax.xml.transform.Source; import javax.xml.transform.SourceLocator; -import org.xml.sax.*; -import org.xml.sax.ext.*; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; /** * This class implements a DTM that tends to be optimized more for speed than @@ -82,7 +96,6 @@ * * Made protected rather than private so SAX2RTFDTM can access it. */ - //private FastStringBuffer m_chars = new FastStringBuffer(13, 13); protected FastStringBuffer m_chars; /** This vector holds offset and length data. @@ -102,8 +115,7 @@ /** Namespace support, only relevent at construction time. * Made protected rather than private so SAX2RTFDTM can access it. */ - transient protected java.util.Vector m_prefixMappings = - new java.util.Vector(); + transient protected Vector m_prefixMappings = new Vector<>(); /** Namespace support, only relevent at construction time. * Made protected rather than private so SAX2RTFDTM can access it. @@ -164,7 +176,7 @@ * Vector of entities. Each record is composed of four Strings: * publicId, systemID, notationName, and name. */ - private Vector m_entities = null; + private ArrayList m_entities = null; /** m_entities public ID offset. */ private static final int ENTITY_FIELD_PUBLICID = 0; @@ -196,13 +208,15 @@ */ protected boolean m_useSourceLocationProperty = false; - /** Made protected for access by SAX2RTFDTM. + /** Made protected for access by SAX2RTFDTM. */ protected StringVector m_sourceSystemId; - /** Made protected for access by SAX2RTFDTM. + + /** Made protected for access by SAX2RTFDTM. */ protected IntVector m_sourceLine; - /** Made protected for access by SAX2RTFDTM. + + /** Made protected for access by SAX2RTFDTM. */ protected IntVector m_sourceColumn; @@ -252,23 +266,19 @@ boolean usePrevsib, boolean newNameTable) { - super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable); // %OPT% Use smaller sizes for all internal storage units when // the blocksize is small. This reduces the cost of creating an RTF. - if (blocksize <= 64) - { + if (blocksize <= 64) { m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL); m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL); m_valuesOrPrefixes = new DTMStringPool(16); m_chars = new FastStringBuffer(7, 10); m_contextIndexes = new IntStack(4); m_parents = new IntStack(4); - } - else - { + } else { m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS); m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS); m_valuesOrPrefixes = new DTMStringPool(); @@ -289,7 +299,7 @@ // m_useSourceLocationProperty=com.sun.org.apache.xalan.internal.processor.TransformerFactoryImpl.m_source_location; m_useSourceLocationProperty = mgr.getSource_location(); m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector() : null; - m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null; + m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null; m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector() : null; } @@ -297,8 +307,7 @@ * Set whether information about document source location * should be maintained or not. */ - public void setUseSourceLocation(boolean useSourceLocation) - { + public void setUseSourceLocation(boolean useSourceLocation) { m_useSourceLocationProperty = useSourceLocation; } @@ -309,17 +318,14 @@ * * @return The data or qualified name, or DTM.NULL. */ - protected int _dataOrQName(int identity) - { - + protected int _dataOrQName(int identity) { if (identity < m_size) return m_dataOrQName.elementAt(identity); // Check to see if the information requested has been processed, and, // if not, advance the iterator until we the information has been // processed. - while (true) - { + while (true) { boolean isMore = nextNode(); if (!isMore) @@ -332,8 +338,7 @@ /** * Ask the CoRoutine parser to doTerminate and clear the reference. */ - public void clearCoRoutine() - { + public void clearCoRoutine() { clearCoRoutine(true); } @@ -344,11 +349,8 @@ * @param callDoTerminate true of doTerminate should be called on the * coRoutine parser. */ - public void clearCoRoutine(boolean callDoTerminate) - { - - if (null != m_incrementalSAXSource) - { + public void clearCoRoutine(boolean callDoTerminate) { + if (null != m_incrementalSAXSource) { if (callDoTerminate) m_incrementalSAXSource.deliverMoreNodes(false); @@ -368,9 +370,7 @@ * @param incrementalSAXSource The parser that we want to recieve events from * on demand. */ - public void setIncrementalSAXSource(IncrementalSAXSource incrementalSAXSource) - { - + public void setIncrementalSAXSource(IncrementalSAXSource incrementalSAXSource) { // Establish coroutine link so we can request more data // // Note: It's possible that some versions of IncrementalSAXSource may @@ -406,11 +406,9 @@ * Note that IncrementalSAXSource_Filter is package private, hence * it can be statically referenced using instanceof (CR 6537912). */ - public ContentHandler getContentHandler() - { - - if (m_incrementalSAXSource.getClass() - .getName().equals("com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Filter")) + public ContentHandler getContentHandler() { + if (m_incrementalSAXSource.getClass().getName() + .equals("com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Filter")) return (ContentHandler) m_incrementalSAXSource; else return this; @@ -429,11 +427,9 @@ * Note that IncrementalSAXSource_Filter is package private, hence * it can be statically referenced using instanceof (CR 6537912). */ - public LexicalHandler getLexicalHandler() - { - - if (m_incrementalSAXSource.getClass() - .getName().equals("com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Filter")) + public LexicalHandler getLexicalHandler() { + if (m_incrementalSAXSource.getClass().getName() + .equals("com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Filter")) return (LexicalHandler) m_incrementalSAXSource; else return this; @@ -444,8 +440,7 @@ * * @return null if this model doesn't respond to SAX entity ref events. */ - public EntityResolver getEntityResolver() - { + public EntityResolver getEntityResolver() { return this; } @@ -454,8 +449,7 @@ * * @return null if this model doesn't respond to SAX dtd events. */ - public DTDHandler getDTDHandler() - { + public DTDHandler getDTDHandler() { return this; } @@ -464,8 +458,7 @@ * * @return null if this model doesn't respond to SAX error events. */ - public ErrorHandler getErrorHandler() - { + public ErrorHandler getErrorHandler() { return this; } @@ -474,8 +467,7 @@ * * @return null if this model doesn't respond to SAX Decl events. */ - public DeclHandler getDeclHandler() - { + public DeclHandler getDeclHandler() { return this; } @@ -485,8 +477,7 @@ * transformation and the parse run simultaneously. Guidance to the * DTMManager. */ - public boolean needsTwoThreads() - { + public boolean needsTwoThreads() { return null != m_incrementalSAXSource; } @@ -509,9 +500,8 @@ */ public void dispatchCharactersEvents(int nodeHandle, ContentHandler ch, boolean normalize) - throws SAXException + throws SAXException { - int identity = makeNodeIdentity(nodeHandle); if (identity == DTM.NULL) @@ -519,8 +509,7 @@ int type = _type(identity); - if (isTextType(type)) - { + if (isTextType(type)) { int dataIndex = m_dataOrQName.elementAt(identity); int offset = m_data.elementAt(dataIndex); int length = m_data.elementAt(dataIndex + 1); @@ -529,13 +518,10 @@ m_chars.sendNormalizedSAXcharacters(ch, offset, length); else m_chars.sendSAXcharacters(ch, offset, length); - } - else - { + } else { int firstChild = _firstch(identity); - if (DTM.NULL != firstChild) - { + if (DTM.NULL != firstChild) { int offset = -1; int length = 0; int startNode = identity; @@ -545,12 +531,10 @@ do { type = _type(identity); - if (isTextType(type)) - { + if (isTextType(type)) { int dataIndex = _dataOrQName(identity); - if (-1 == offset) - { + if (-1 == offset) { offset = m_data.elementAt(dataIndex); } @@ -560,36 +544,31 @@ identity = getNextNodeIdentity(identity); } while (DTM.NULL != identity && (_parent(identity) >= startNode)); - if (length > 0) - { + if (length > 0) { if(normalize) m_chars.sendNormalizedSAXcharacters(ch, offset, length); else m_chars.sendSAXcharacters(ch, offset, length); } - } - else if(type != DTM.ELEMENT_NODE) - { + } else if(type != DTM.ELEMENT_NODE) { int dataIndex = _dataOrQName(identity); - if (dataIndex < 0) - { + if (dataIndex < 0) { dataIndex = -dataIndex; dataIndex = m_data.elementAt(dataIndex + 1); } String str = m_valuesOrPrefixes.indexToString(dataIndex); - if(normalize) - FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(), - 0, str.length(), ch); - else - ch.characters(str.toCharArray(), 0, str.length()); + if(normalize) + FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(), + 0, str.length(), ch); + else + ch.characters(str.toCharArray(), 0, str.length()); } } } - /** * Given a node handle, return its DOM-style node name. This will * include names such as #text or #document. @@ -599,39 +578,29 @@ * %REVIEW% Document when empty string is possible... * %REVIEW-COMMENT% It should never be empty, should it? */ - public String getNodeName(int nodeHandle) - { - + public String getNodeName(int nodeHandle) { int expandedTypeID = getExpandedTypeID(nodeHandle); // If just testing nonzero, no need to shift... int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID); - if (0 == namespaceID) - { + if (0 == namespaceID) { // Don't retrieve name until/unless needed // String name = m_expandedNameTable.getLocalName(expandedTypeID); int type = getNodeType(nodeHandle); - if (type == DTM.NAMESPACE_NODE) - { + if (type == DTM.NAMESPACE_NODE) { if (null == m_expandedNameTable.getLocalName(expandedTypeID)) return "xmlns"; else return "xmlns:" + m_expandedNameTable.getLocalName(expandedTypeID); - } - else if (0 == m_expandedNameTable.getLocalNameID(expandedTypeID)) - { + } else if (0 == m_expandedNameTable.getLocalNameID(expandedTypeID)) { return m_fixednames[type]; - } - else + } else return m_expandedNameTable.getLocalName(expandedTypeID); - } - else - { + } else { int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle)); - if (qnameIndex < 0) - { + if (qnameIndex < 0) { qnameIndex = -qnameIndex; qnameIndex = m_data.elementAt(qnameIndex); } @@ -648,27 +617,21 @@ * @param nodeHandle the id of the node. * @return String Name of this node, which may be an empty string. */ - public String getNodeNameX(int nodeHandle) - { - + public String getNodeNameX(int nodeHandle) { int expandedTypeID = getExpandedTypeID(nodeHandle); int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID); - if (0 == namespaceID) - { + if (namespaceID == 0) { String name = m_expandedNameTable.getLocalName(expandedTypeID); if (name == null) return ""; else return name; - } - else - { + } else { int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle)); - if (qnameIndex < 0) - { + if (qnameIndex < 0) { qnameIndex = -qnameIndex; qnameIndex = m_data.elementAt(qnameIndex); } @@ -686,11 +649,9 @@ * @return true if the attribute was specified; * false if it was defaulted. */ - public boolean isAttributeSpecified(int attributeHandle) - { - + public boolean isAttributeSpecified(int attributeHandle) { // I'm not sure if I want to do anything with this... - return true; // ?? + return true; // ?? } /** @@ -701,9 +662,7 @@ * * @return the system identifier String object, or null if there is none. */ - public String getDocumentTypeDeclarationSystemIdentifier() - { - + public String getDocumentTypeDeclarationSystemIdentifier() { /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMDefaultBase abstract method */ error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!"); @@ -717,14 +676,11 @@ * @param identity The node identity (index). * @return identity+1, or DTM.NULL. */ - protected int getNextNodeIdentity(int identity) - { - + protected int getNextNodeIdentity(int identity) { identity += 1; - while (identity >= m_size) - { - if (null == m_incrementalSAXSource) + while (identity >= m_size) { + if (m_incrementalSAXSource == null) return DTM.NULL; nextNode(); @@ -739,10 +695,10 @@ * @param nodeHandle The node ID. * @param ch A non-null reference to a ContentHandler. * - * @throws org.xml.sax.SAXException + * @throws SAXException */ - public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch) - throws org.xml.sax.SAXException + public void dispatchToEvents(int nodeHandle, ContentHandler ch) + throws SAXException { DTMTreeWalker treeWalker = m_walker; @@ -1087,28 +1043,22 @@ * @return String containing the URI of the Unparsed Entity, or an * empty string if no such entity exists. */ - public String getUnparsedEntityURI(String name) - { - + public String getUnparsedEntityURI(String name) { String url = ""; - if (null == m_entities) + if (null == m_entities) { return url; + } int n = m_entities.size(); - for (int i = 0; i < n; i += ENTITY_FIELDS_PER) - { - String ename = (String) m_entities.elementAt(i + ENTITY_FIELD_NAME); + for (int i = 0; i < n; i += ENTITY_FIELDS_PER) { + String ename = m_entities.get(i + ENTITY_FIELD_NAME); - if (null != ename && ename.equals(name)) - { - String nname = (String) m_entities.elementAt(i - + ENTITY_FIELD_NOTATIONNAME); + if (null != ename && ename.equals(name)) { + String nname = m_entities.get(i + ENTITY_FIELD_NOTATIONNAME); - if (null != nname) - { - + if (null != nname) { // The draft says: "The XSLT processor may use the public // identifier to generate a URI for the entity instead of the URI // specified in the system identifier. If the XSLT processor does @@ -1118,11 +1068,10 @@ // the resource containing the entity declaration as the base // URI [RFC2396]." // So I'm falling a bit short here. - url = (String) m_entities.elementAt(i + ENTITY_FIELD_SYSTEMID); + url = m_entities.get(i + ENTITY_FIELD_SYSTEMID); - if (null == url) - { - url = (String) m_entities.elementAt(i + ENTITY_FIELD_PUBLICID); + if (null == url) { + url = m_entities.get(i + ENTITY_FIELD_PUBLICID); } } @@ -1400,26 +1349,18 @@ * * @return The prefix if there is one, or null. */ - public String getPrefix(String qname, String uri) - { - + public String getPrefix(String qname, String uri) { String prefix; int uriIndex = -1; - if (null != uri && uri.length() > 0) - { - - do - { + if (null != uri && uri.length() > 0) { + do { uriIndex = m_prefixMappings.indexOf(uri, ++uriIndex); - } while ( (uriIndex & 0x01) == 0); + } while ((uriIndex & 0x01) == 0); - if (uriIndex >= 0) - { - prefix = (String) m_prefixMappings.elementAt(uriIndex - 1); - } - else if (null != qname) - { + if (uriIndex >= 0) { + prefix = m_prefixMappings.elementAt(uriIndex - 1); + } else if (null != qname) { int indexOfNSSep = qname.indexOf(':'); if (qname.equals("xmlns")) @@ -1429,33 +1370,24 @@ else prefix = (indexOfNSSep > 0) ? qname.substring(0, indexOfNSSep) : null; - } - else - { + } else { prefix = null; } - } - else if (null != qname) - { + } else if (null != qname) { int indexOfNSSep = qname.indexOf(':'); - if (indexOfNSSep > 0) - { + if (indexOfNSSep > 0) { if (qname.startsWith("xmlns:")) prefix = qname.substring(indexOfNSSep + 1); else prefix = qname.substring(0, indexOfNSSep); - } - else - { + } else { if (qname.equals("xmlns")) prefix = ""; else prefix = null; } - } - else - { + } else { prefix = null; } @@ -1470,38 +1402,31 @@ * * @return The prefix if there is one, or null. */ - public int getIdForNamespace(String uri) - { - + public int getIdForNamespace(String uri) { return m_valuesOrPrefixes.stringToIndex(uri); - } - /** + /** * Get a prefix either from the qname or from the uri mapping, or just make * one up! * * @return The prefix if there is one, or null. */ - public String getNamespaceURI(String prefix) - { - + public String getNamespaceURI(String prefix) { String uri = ""; int prefixIndex = m_contextIndexes.peek() - 1 ; - if(null == prefix) + if (null == prefix) { prefix = ""; + } - do - { - prefixIndex = m_prefixMappings.indexOf(prefix, ++prefixIndex); - } while ( (prefixIndex >= 0) && (prefixIndex & 0x01) == 0x01); + do { + prefixIndex = m_prefixMappings.indexOf(prefix, ++prefixIndex); + } while ((prefixIndex >= 0) && (prefixIndex & 0x01) == 0x01); - if (prefixIndex > -1) - { - uri = (String) m_prefixMappings.elementAt(prefixIndex + 1); - } - + if (prefixIndex > -1) { + uri = m_prefixMappings.elementAt(prefixIndex + 1); + } return uri; } @@ -1578,7 +1503,7 @@ * default behaviour. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.EntityResolver#resolveEntity + * @see EntityResolver#resolveEntity * * @throws SAXException */ @@ -1605,7 +1530,7 @@ * @param systemId The notation system identifier. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.DTDHandler#notationDecl + * @see DTDHandler#notationDecl * * @throws SAXException */ @@ -1630,41 +1555,35 @@ * @param notationName The name of the associated notation. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.DTDHandler#unparsedEntityDecl + * @see DTDHandler#unparsedEntityDecl * * @throws SAXException */ - public void unparsedEntityDecl( - String name, String publicId, String systemId, String notationName) - throws SAXException + public void unparsedEntityDecl(String name, String publicId, String systemId, + String notationName) throws SAXException { - - if (null == m_entities) - { - m_entities = new Vector(); + if (null == m_entities) { + m_entities = new ArrayList<>(); } - try - { + try { systemId = SystemIDResolver.getAbsoluteURI(systemId, getDocumentBaseURI()); - } - catch (Exception e) - { - throw new org.xml.sax.SAXException(e); + } catch (Exception e) { + throw new SAXException(e); } // private static final int ENTITY_FIELD_PUBLICID = 0; - m_entities.addElement(publicId); + m_entities.add(publicId); // private static final int ENTITY_FIELD_SYSTEMID = 1; - m_entities.addElement(systemId); + m_entities.add(systemId); // private static final int ENTITY_FIELD_NOTATIONNAME = 2; - m_entities.addElement(notationName); + m_entities.add(notationName); // private static final int ENTITY_FIELD_NAME = 3; - m_entities.addElement(name); + m_entities.add(name); } //////////////////////////////////////////////////////////////////// @@ -1679,8 +1598,8 @@ * with other document events.

* * @param locator A locator for all SAX document events. - * @see org.xml.sax.ContentHandler#setDocumentLocator - * @see org.xml.sax.Locator + * @see ContentHandler#setDocumentLocator + * @see Locator */ public void setDocumentLocator(Locator locator) { @@ -1693,7 +1612,7 @@ * * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#startDocument + * @see ContentHandler#startDocument */ public void startDocument() throws SAXException { @@ -1716,7 +1635,7 @@ * * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#endDocument + * @see ContentHandler#endDocument */ public void endDocument() throws SAXException { @@ -1754,7 +1673,7 @@ * @param uri The Namespace URI mapped to the prefix. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#startPrefixMapping + * @see ContentHandler#startPrefixMapping */ public void startPrefixMapping(String prefix, String uri) throws SAXException @@ -1780,7 +1699,7 @@ * @param prefix The Namespace prefix being declared. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#endPrefixMapping + * @see ContentHandler#endPrefixMapping */ public void endPrefixMapping(String prefix) throws SAXException { @@ -1815,16 +1734,13 @@ * @return true if the declaration has already been declared in the * current context. */ - protected boolean declAlreadyDeclared(String prefix) - { - + protected boolean declAlreadyDeclared(String prefix) { int startDecls = m_contextIndexes.peek(); - java.util.Vector prefixMappings = m_prefixMappings; + Vector prefixMappings = m_prefixMappings; int nDecls = prefixMappings.size(); - for (int i = startDecls; i < nDecls; i += 2) - { - String prefixDecl = (String) prefixMappings.elementAt(i); + for (int i = startDecls; i < nDecls; i += 2) { + String prefixDecl = prefixMappings.elementAt(i); if (prefixDecl == null) continue; @@ -1836,7 +1752,7 @@ return false; } - boolean m_pastFirstElement=false; + boolean m_pastFirstElement=false; /** * Receive notification of the start of an element. @@ -1857,35 +1773,38 @@ * @param attributes The specified or defaulted attributes. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#startElement + * @see ContentHandler#startElement */ - public void startElement( - String uri, String localName, String qName, Attributes attributes) - throws SAXException + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { - if (DEBUG) - { - System.out.println("startElement: uri: " + uri + ", localname: " - + localName + ", qname: "+qName+", atts: " + attributes); + if (DEBUG) { + System.out.println("startElement: uri: " + uri + + ", localname: " + localName + + ", qname: "+qName+", atts: " + attributes); - boolean DEBUG_ATTRS=true; - if(DEBUG_ATTRS & attributes!=null) - { - int n = attributes.getLength(); - if(n==0) - System.out.println("\tempty attribute list"); - else for (int i = 0; i < n; i++) - System.out.println("\t attr: uri: " + attributes.getURI(i) + - ", localname: " + attributes.getLocalName(i) + - ", qname: " + attributes.getQName(i) + - ", type: " + attributes.getType(i) + - ", value: " + attributes.getValue(i) - ); - } - } + boolean DEBUG_ATTRS=true; + if (DEBUG_ATTRS & attributes!=null) { + int n = attributes.getLength(); + if (n==0) { + System.out.println("\tempty attribute list"); + } else for (int i = 0; i < n; i++) { + System.out.println("\t attr: uri: " + attributes.getURI(i) + + ", localname: " + attributes.getLocalName(i) + + ", qname: " + attributes.getQName(i) + + ", type: " + attributes.getType(i) + + ", value: " + attributes.getValue(i)); + } + } + } charactersFlush(); + if ((localName == null || localName.isEmpty()) && + (uri == null || uri.isEmpty())) { + localName = qName; + } + int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE); String prefix = getPrefix(qName, uri); int prefixIndex = (null != prefix) @@ -1894,20 +1813,18 @@ int elemNode = addNode(DTM.ELEMENT_NODE, exName, m_parents.peek(), m_previous, prefixIndex, true); - if(m_indexing) + if (m_indexing) indexNode(exName, elemNode); - m_parents.push(elemNode); int startDecls = m_contextIndexes.peek(); int nDecls = m_prefixMappings.size(); int prev = DTM.NULL; - if(!m_pastFirstElement) - { + if (!m_pastFirstElement) { // SPECIAL CASE: Implied declaration at root element - prefix="xml"; + prefix = "xml"; String declURL = "http://www.w3.org/XML/1998/namespace"; exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); int val = m_valuesOrPrefixes.stringToIndex(declURL); @@ -1916,14 +1833,13 @@ m_pastFirstElement=true; } - for (int i = startDecls; i < nDecls; i += 2) - { - prefix = (String) m_prefixMappings.elementAt(i); + for (int i = startDecls; i < nDecls; i += 2) { + prefix = m_prefixMappings.elementAt(i); if (prefix == null) continue; - String declURL = (String) m_prefixMappings.elementAt(i + 1); + String declURL = m_prefixMappings.elementAt(i + 1); exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); @@ -1935,8 +1851,7 @@ int n = attributes.getLength(); - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { String attrUri = attributes.getURI(i); String attrQName = attributes.getQName(i); String valString = attributes.getValue(i); @@ -1947,17 +1862,13 @@ String attrLocalName = attributes.getLocalName(i); - if ((null != attrQName) - && (attrQName.equals("xmlns") - || attrQName.startsWith("xmlns:"))) - { + if ((null != attrQName) && + (attrQName.equals("xmlns") || attrQName.startsWith("xmlns:"))) { if (declAlreadyDeclared(prefix)) continue; // go to the next attribute. nodeType = DTM.NAMESPACE_NODE; - } - else - { + } else { nodeType = DTM.ATTRIBUTE_NODE; if (attributes.getType(i).equalsIgnoreCase("ID")) @@ -1966,15 +1877,13 @@ // Bit of a hack... if somehow valString is null, stringToIndex will // return -1, which will make things very unhappy. - if(null == valString) + if (null == valString) valString = ""; int val = m_valuesOrPrefixes.stringToIndex(valString); //String attrLocalName = attributes.getLocalName(i); - if (null != prefix) - { - + if (null != prefix) { prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName); int dataIndex = m_data.size(); @@ -1993,8 +1902,7 @@ if (DTM.NULL != prev) m_nextsib.setElementAt(DTM.NULL,prev); - if (null != m_wsfilter) - { + if (null != m_wsfilter) { short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this); boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ? getShouldStripWhitespace() @@ -2026,7 +1934,7 @@ * empty string if qualified names are not available. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#endElement + * @see ContentHandler#endElement */ public void endElement(String uri, String localName, String qName) throws SAXException @@ -2074,7 +1982,7 @@ * character array. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#characters + * @see ContentHandler#characters */ public void characters(char ch[], int start, int length) throws SAXException { @@ -2109,7 +2017,7 @@ * character array. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#ignorableWhitespace + * @see ContentHandler#ignorableWhitespace */ public void ignorableWhitespace(char ch[], int start, int length) throws SAXException @@ -2133,7 +2041,7 @@ * none is supplied. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#processingInstruction + * @see ContentHandler#processingInstruction */ public void processingInstruction(String target, String data) throws SAXException @@ -2163,7 +2071,7 @@ * @param name The name of the skipped entity. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#processingInstruction + * @see ContentHandler#processingInstruction */ public void skippedEntity(String name) throws SAXException { @@ -2187,8 +2095,8 @@ * @param e The warning information encoded as an exception. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ErrorHandler#warning - * @see org.xml.sax.SAXParseException + * @see ErrorHandler#warning + * @see SAXParseException */ public void warning(SAXParseException e) throws SAXException { @@ -2208,8 +2116,8 @@ * @param e The warning information encoded as an exception. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ErrorHandler#warning - * @see org.xml.sax.SAXParseException + * @see ErrorHandler#warning + * @see SAXParseException */ public void error(SAXParseException e) throws SAXException { @@ -2230,8 +2138,8 @@ * @param e The error information encoded as an exception. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ErrorHandler#fatalError - * @see org.xml.sax.SAXParseException + * @see ErrorHandler#fatalError + * @see SAXParseException */ public void fatalError(SAXParseException e) throws SAXException { @@ -2299,7 +2207,7 @@ * @param value The replacement text of the entity. * @throws SAXException The application may raise an exception. * @see #externalEntityDecl - * @see org.xml.sax.DTDHandler#unparsedEntityDecl + * @see DTDHandler#unparsedEntityDecl */ public void internalEntityDecl(String name, String value) throws SAXException @@ -2321,7 +2229,7 @@ * @param systemId The declared system identifier of the entity. * @throws SAXException The application may raise an exception. * @see #internalEntityDecl - * @see org.xml.sax.DTDHandler#unparsedEntityDecl + * @see DTDHandler#unparsedEntityDecl */ public void externalEntityDecl( String name, String publicId, String systemId) throws SAXException @@ -2386,15 +2294,15 @@ * properly nested within start/end entity events.

* *

Note that skipped entities will be reported through the - * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity} + * {@link ContentHandler#skippedEntity skippedEntity} * event, which is part of the ContentHandler interface.

* * @param name The name of the entity. If it is a parameter * entity, the name will begin with '%'. * @throws SAXException The application may raise an exception. * @see #endEntity - * @see org.xml.sax.ext.DeclHandler#internalEntityDecl - * @see org.xml.sax.ext.DeclHandler#externalEntityDecl + * @see DeclHandler#internalEntityDecl + * @see DeclHandler#externalEntityDecl */ public void startEntity(String name) throws SAXException { @@ -2419,7 +2327,7 @@ * Report the start of a CDATA section. * *

The contents of the CDATA section will be reported through - * the regular {@link org.xml.sax.ContentHandler#characters + * the regular {@link ContentHandler#characters * characters} event.

* * @throws SAXException The application may raise an exception. diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM2.java --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM2.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM2.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,13 +1,13 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 1999-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -17,13 +17,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SAX2DTM2.java,v 1.2.4.1 2005/09/15 08:15:12 suresh_emailid Exp $ - */ + package com.sun.org.apache.xml.internal.dtm.ref.sax2dtm; -import com.sun.org.apache.xml.internal.dtm.*; -import com.sun.org.apache.xml.internal.dtm.ref.*; +import com.sun.org.apache.xml.internal.dtm.DTM; +import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; +import com.sun.org.apache.xml.internal.dtm.DTMException; +import com.sun.org.apache.xml.internal.dtm.DTMManager; +import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; +import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; +import com.sun.org.apache.xml.internal.dtm.ref.ExpandedNameTable; +import com.sun.org.apache.xml.internal.dtm.ref.ExtendedType; import com.sun.org.apache.xml.internal.utils.FastStringBuffer; import com.sun.org.apache.xml.internal.utils.XMLString; import com.sun.org.apache.xml.internal.utils.XMLStringDefault; @@ -31,11 +35,12 @@ import com.sun.org.apache.xml.internal.res.XMLMessages; import com.sun.org.apache.xml.internal.res.XMLErrorResources; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; - +import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector; +import java.util.ArrayList; import javax.xml.transform.Source; -import java.util.Vector; -import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector; -import org.xml.sax.*; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; /** * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation. @@ -53,10 +58,6 @@ * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the * SAX2DTM model, please extend from SAX2DTM instead of this class. *

- * TODO: This class is currently only used by XSLTC. We need to investigate the possibility - * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant - * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case. - *

* %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful * when making changes here! */ @@ -87,11 +88,10 @@ */ public DTMAxisIterator setStartNode(int node) { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); - if (_isRestartable) - { + if (_isRestartable) { _startNode = node; _currentNode = (node == DTM.NULL) ? DTM.NULL : _firstch2(makeNodeIdentity(node)); @@ -108,8 +108,7 @@ * @return The next node handle in the iteration, or END if no more * are available. */ - public int next() - { + public int next() { if (_currentNode != NULL) { int node = _currentNode; _currentNode = _nextsib2(node); @@ -139,13 +138,11 @@ * * @return A DTMAxisIterator set to the start of the iteration. */ - public DTMAxisIterator setStartNode(int node) - { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + public DTMAxisIterator setStartNode(int node) { + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); - if (_isRestartable) - { + if (_isRestartable) { _startNode = node; if (node != DTM.NULL) @@ -229,8 +226,7 @@ * * @param nodeType The extended type ID being requested. */ - public TypedChildrenIterator(int nodeType) - { + public TypedChildrenIterator(int nodeType) { _nodeType = nodeType; } @@ -242,17 +238,14 @@ * * @return A DTMAxisIterator set to the start of the iteration. */ - public DTMAxisIterator setStartNode(int node) - { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + public DTMAxisIterator setStartNode(int node) { + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); - if (_isRestartable) - { + if (_isRestartable) { _startNode = node; - _currentNode = (node == DTM.NULL) - ? DTM.NULL - : _firstch2(makeNodeIdentity(_startNode)); + _currentNode = (node == DTM.NULL) ? DTM.NULL : + _firstch2(makeNodeIdentity(_startNode)); return resetPosition(); } @@ -265,8 +258,7 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { + public int next() { int node = _currentNode; if (node == DTM.NULL) return DTM.NULL; @@ -301,14 +293,12 @@ _currentNode = _nextsib2(node); return returnNode(makeNodeHandle(node)); } - } /** * Return the node at the given position. */ - public int getNodeByPosition(int position) - { + public int getNodeByPosition(int position) { if (position <= 0) return DTM.NULL; @@ -327,8 +317,7 @@ node = _nextsib2(node); } return NULL; - } - else { + } else { while (node != DTM.NULL) { if (_exptype2(node) >= DTM.NTYPES) { pos++; @@ -415,13 +404,11 @@ * * @return A DTMAxisIterator set to the start of the iteration. */ - public DTMAxisIterator setStartNode(int node) - { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + public DTMAxisIterator setStartNode(int node) { + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); - if (_isRestartable) - { + if (_isRestartable) { _startNode = node; _currentNode = makeNodeIdentity(node); @@ -436,8 +423,7 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { + public int next() { _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL : _nextsib2(_currentNode); return returnNode(makeNodeHandle(_currentNode)); @@ -460,8 +446,7 @@ * * @param type The extended type ID being requested. */ - public TypedFollowingSiblingIterator(int type) - { + public TypedFollowingSiblingIterator(int type) { _nodeType = type; } @@ -470,8 +455,7 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { + public int next() { if (_currentNode == DTM.NULL) { return DTM.NULL; } @@ -481,8 +465,7 @@ if (nodeType != DTM.ELEMENT_NODE) { while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {} - } - else { + } else { while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {} } @@ -498,8 +481,7 @@ /** * Iterator that returns attribute nodes (of what nodes?) */ - public final class AttributeIterator extends InternalAxisIteratorBase - { + public final class AttributeIterator extends InternalAxisIteratorBase { // assumes caller will pass element nodes @@ -511,13 +493,11 @@ * * @return A DTMAxisIterator set to the start of the iteration. */ - public DTMAxisIterator setStartNode(int node) - { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + public DTMAxisIterator setStartNode(int node) { + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); - if (_isRestartable) - { + if (_isRestartable) { _startNode = node; _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node)); @@ -532,9 +512,7 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { - + public int next() { final int node = _currentNode; if (node != NULL) { @@ -561,8 +539,7 @@ * * @param nodeType The extended type ID that is requested. */ - public TypedAttributeIterator(int nodeType) - { + public TypedAttributeIterator(int nodeType) { _nodeType = nodeType; } @@ -576,14 +553,10 @@ * * @return A DTMAxisIterator set to the start of the iteration. */ - public DTMAxisIterator setStartNode(int node) - { - if (_isRestartable) - { + public DTMAxisIterator setStartNode(int node) { + if (_isRestartable) { _startNode = node; - _currentNode = getTypedAttribute(node, _nodeType); - return resetPosition(); } @@ -595,9 +568,7 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { - + public int next() { final int node = _currentNode; // singleton iterator, since there can only be one attribute of @@ -624,8 +595,7 @@ * * @return true. */ - public boolean isReverse() - { + public boolean isReverse() { return true; } @@ -637,30 +607,25 @@ * * @return A DTMAxisIterator set to the start of the iteration. */ - public DTMAxisIterator setStartNode(int node) - { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + public DTMAxisIterator setStartNode(int node) { + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); - if (_isRestartable) - { + if (_isRestartable) { _startNode = node; node = _startNodeID = makeNodeIdentity(node); - if(node == NULL) - { + if(node == NULL) { _currentNode = node; return resetPosition(); } int type = _type2(node); - if(ExpandedNameTable.ATTRIBUTE == type - || ExpandedNameTable.NAMESPACE == type ) + if (ExpandedNameTable.ATTRIBUTE == type || + ExpandedNameTable.NAMESPACE == type) { _currentNode = node; - } - else - { + } else { // Be careful to handle the Document node properly _currentNode = _parent2(node); if(NULL!=_currentNode) @@ -680,18 +645,12 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { - - if (_currentNode == _startNodeID || _currentNode == DTM.NULL) - { + public int next() { + if (_currentNode == _startNodeID || _currentNode == DTM.NULL) { return NULL; - } - else - { + } else { final int node = _currentNode; _currentNode = _nextsib2(node); - return returnNode(makeNodeHandle(node)); } } @@ -714,8 +673,7 @@ * * @param type The extended type ID being requested. */ - public TypedPrecedingSiblingIterator(int type) - { + public TypedPrecedingSiblingIterator(int type) { _nodeType = type; } @@ -724,8 +682,7 @@ * * @return The next node handle in the iteration, or END. */ - public int next() - { + public int next() { int node = _currentNode; final int nodeType = _nodeType; @@ -735,8 +692,7 @@ while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) { node = _nextsib2(node); } - } - else { + } else { while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) { node = _nextsib2(node); } @@ -745,8 +701,7 @@ if (node == DTM.NULL || node == startNodeID) { _currentNode = NULL; return NULL; - } - else { + } else { _currentNode = _nextsib2(node); return returnNode(makeNodeHandle(node)); } @@ -755,8 +710,7 @@ /** * Return the index of the last node in this iterator. */ - public int getLast() - { + public int getLast() { if (_last != -1) return _last; @@ -774,8 +728,7 @@ } node = _nextsib2(node); } - } - else { + } else { while (node != NULL && node != startNodeID) { if (_exptype2(node) >= DTM.NTYPES) { last++; @@ -860,7 +813,7 @@ */ public DTMAxisIterator setStartNode(int node) { -//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily + //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily if (node == DTMDefaultBase.ROOTNODE) node = getDocument(); if (_isRestartable) @@ -1799,9 +1752,7 @@ // %OPT% These values are unlikely to be equal. Storing // them in a plain Vector is more efficient than storing in the // DTMStringPool because we can save the cost for hash calculation. - // - // %REVISIT% Do we need a custom class (e.g. StringVector) here? - protected Vector m_values; + protected ArrayList m_values; // The current index into the m_values Vector. private int m_valueIndex = 0; @@ -1881,9 +1832,8 @@ m_buildIdIndex = buildIdIndex; // Some documents do not have attribute nodes. That is why - // we set the initial size of this Vector to be small and set - // the increment to a bigger number. - m_values = new Vector(32, 512); + // we set the initial size of this ArrayList to be small. + m_values = new ArrayList<>(32); m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS; @@ -1953,10 +1903,7 @@ * @param identity A node identity, which must not be equal to * DTM.NULL */ - public final int _firstch2(int identity) - { - //return m_firstch.elementAt(identity); - + public final int _firstch2(int identity) { if (identity < m_blocksize) return m_firstch_map0[identity]; else @@ -1969,10 +1916,7 @@ * @param identity A node identity, which must not be equal to * DTM.NULL */ - public final int _parent2(int identity) - { - //return m_parent.elementAt(identity); - + public final int _parent2(int identity) { if (identity < m_blocksize) return m_parent_map0[identity]; else @@ -1985,9 +1929,7 @@ * @param identity A node identity, which must not be equal to * DTM.NULL */ - public final int _type2(int identity) - { - //int eType = _exptype2(identity); + public final int _type2(int identity) { int eType; if (identity < m_blocksize) eType = m_exptype_map0[identity]; @@ -2006,12 +1948,9 @@ *

This one is only used by DOMAdapter.getExpandedTypeID(int), which * is mostly called from the compiled translets. */ - public final int getExpandedTypeID2(int nodeHandle) - { + public final int getExpandedTypeID2(int nodeHandle) { int nodeID = makeNodeIdentity(nodeHandle); - //return (nodeID != NULL) ? _exptype2(nodeID) : NULL; - if (nodeID != NULL) { if (nodeID < m_blocksize) return m_exptype_map0[nodeID]; @@ -2026,12 +1965,10 @@ * END of DTM base accessor interfaces *************************************************************************/ - /** * Return the node type from the expanded type */ - public final int _exptype2Type(int exptype) - { + public final int _exptype2Type(int exptype) { if (NULL != exptype) return m_extendedTypes[exptype].getNodeType(); else @@ -2046,16 +1983,14 @@ * * @return The prefix if there is one, or null. */ - public int getIdForNamespace(String uri) - { + public int getIdForNamespace(String uri) { int index = m_values.indexOf(uri); - if (index < 0) - { - m_values.addElement(uri); + if (index < 0) { + m_values.add(uri); return m_valueIndex++; + } else { + return index; } - else - return index; } /** @@ -2079,15 +2014,25 @@ * @param attributes The specified or defaulted attributes. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#startElement + * @see ContentHandler#startElement */ - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { - charactersFlush(); - int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE); + // in case URI and localName are empty, the input is not using the + // namespaces feature. Then we should take the part after the last + // colon of qName as localName (strip all namespace prefixes) + if ((uri == null || uri.isEmpty()) && + (localName == null || localName.isEmpty())) + { + final int colon = qName.lastIndexOf(':'); + localName = (colon > -1) ? qName.substring(colon + 1) : qName; + } + + int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, + DTM.ELEMENT_NODE); int prefixIndex = (qName.length() != localName.length()) ? m_valuesOrPrefixes.stringToIndex(qName) : 0; @@ -2095,7 +2040,7 @@ int elemNode = addNode(DTM.ELEMENT_NODE, exName, m_parents.peek(), m_previous, prefixIndex, true); - if(m_indexing) + if (m_indexing) indexNode(exName, elemNode); m_parents.push(elemNode); @@ -2104,31 +2049,31 @@ int nDecls = m_prefixMappings.size(); String prefix; - if(!m_pastFirstElement) - { + if (!m_pastFirstElement) { // SPECIAL CASE: Implied declaration at root element - prefix="xml"; + prefix = "xml"; String declURL = "http://www.w3.org/XML/1998/namespace"; - exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); - m_values.addElement(declURL); + exName = m_expandedNameTable.getExpandedTypeID(null, prefix, + DTM.NAMESPACE_NODE); + m_values.add(declURL); int val = m_valueIndex++; addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false); m_pastFirstElement=true; } - for (int i = startDecls; i < nDecls; i += 2) - { - prefix = (String) m_prefixMappings.elementAt(i); + for (int i = startDecls; i < nDecls; i += 2) { + prefix = m_prefixMappings.elementAt(i); if (prefix == null) continue; - String declURL = (String) m_prefixMappings.elementAt(i + 1); - - exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); - - m_values.addElement(declURL); + String declURL = m_prefixMappings.elementAt(i + 1); + + exName = m_expandedNameTable.getExpandedTypeID(null, prefix, + DTM.NAMESPACE_NODE); + + m_values.add(declURL); int val = m_valueIndex++; addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false); @@ -2136,28 +2081,37 @@ int n = attributes.getLength(); - for (int i = 0; i < n; i++) - { + for (int i = 0; i < n; i++) { String attrUri = attributes.getURI(i); + String attrLocalName = attributes.getLocalName(i); String attrQName = attributes.getQName(i); String valString = attributes.getValue(i); + // in case URI and localName are empty, the input is not using the + // namespaces feature. Then we should take the part after the last + // colon of qName as localName (strip all namespace prefixes) + // When the URI is empty but localName has colons then we can also + // assume non namespace aware and prefixes can be stripped + if (attrUri == null || attrUri.isEmpty()) { + if (attrLocalName == null || attrLocalName.isEmpty()) { + final int colon = attrQName.lastIndexOf(':'); + attrLocalName = (colon > -1) ? attrQName.substring(colon + 1) : attrQName; + } else { + final int colon = attrLocalName.lastIndexOf(':'); + attrLocalName = (colon > -1) ? attrLocalName.substring(colon + 1) : attrLocalName; + } + } + int nodeType; - - String attrLocalName = attributes.getLocalName(i); - - if ((null != attrQName) - && (attrQName.equals("xmlns") - || attrQName.startsWith("xmlns:"))) + if ((null != attrQName) && + (attrQName.equals("xmlns") || attrQName.startsWith("xmlns:"))) { prefix = getPrefix(attrQName, attrUri); if (declAlreadyDeclared(prefix)) continue; // go to the next attribute. nodeType = DTM.NAMESPACE_NODE; - } - else - { + } else { nodeType = DTM.ATTRIBUTE_NODE; if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID")) @@ -2166,36 +2120,31 @@ // Bit of a hack... if somehow valString is null, stringToIndex will // return -1, which will make things very unhappy. - if(null == valString) + if (null == valString) valString = ""; - m_values.addElement(valString); + m_values.add(valString); int val = m_valueIndex++; - if (attrLocalName.length() != attrQName.length()) - { - + if (attrLocalName.length() != attrQName.length()) { prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName); - int dataIndex = m_data.size(); - m_data.addElement(prefixIndex); m_data.addElement(val); - val = -dataIndex; } - exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType); - addNode(nodeType, exName, elemNode, DTM.NULL, val, - false); + exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, + nodeType); + addNode(nodeType, exName, elemNode, DTM.NULL, val, false); } - if (null != m_wsfilter) - { - short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this); - boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) - ? getShouldStripWhitespace() - : (DTMWSFilter.STRIP == wsv); + if (null != m_wsfilter) { + short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), + this); + boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ? + getShouldStripWhitespace() : + (DTMWSFilter.STRIP == wsv); pushShouldStripWhitespace(shouldStrip); } @@ -2223,7 +2172,7 @@ * empty string if qualified names are not available. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#endElement + * @see ContentHandler#endElement */ public void endElement(String uri, String localName, String qName) throws SAXException @@ -2257,9 +2206,7 @@ * @param length The number of characters to use from the array. * @throws SAXException The application may raise an exception. */ - public void comment(char ch[], int start, int length) throws SAXException - { - + public void comment(char ch[], int start, int length) throws SAXException { if (m_insideDTD) // ignore comments if we're inside the DTD return; @@ -2267,7 +2214,7 @@ // %OPT% Saving the comment string in a Vector has a lower cost than // saving it in DTMStringPool. - m_values.addElement(new String(ch, start, length)); + m_values.add(new String(ch, start, length)); int dataIndex = m_valueIndex++; m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE, @@ -2279,13 +2226,10 @@ * * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#startDocument + * @see ContentHandler#startDocument */ - public void startDocument() throws SAXException - { - - int doc = addNode(DTM.DOCUMENT_NODE, - DTM.DOCUMENT_NODE, + public void startDocument() throws SAXException { + int doc = addNode(DTM.DOCUMENT_NODE, DTM.DOCUMENT_NODE, DTM.NULL, DTM.NULL, 0, true); m_parents.push(doc); @@ -2299,10 +2243,9 @@ * * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#endDocument + * @see ContentHandler#endDocument */ - public void endDocument() throws SAXException - { + public void endDocument() throws SAXException { super.endDocument(); // Add a NULL entry to the end of the node arrays as @@ -2334,16 +2277,15 @@ * @return The index identity of the node that was added. */ protected final int addNode(int type, int expandedTypeID, - int parentIndex, int previousSibling, - int dataOrPrefix, boolean canHaveFirstChild) + int parentIndex, int previousSibling, + int dataOrPrefix, boolean canHaveFirstChild) { // Common to all nodes: int nodeIndex = m_size++; // Have we overflowed a DTM Identity's addressing range? //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS)) - if (nodeIndex == m_maxNodeIndex) - { + if (nodeIndex == m_maxNodeIndex) { addNewDTMID(nodeIndex); m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS); } @@ -2366,8 +2308,7 @@ // is called, to handle successive characters() events. // Special handling by type: Declare namespaces, attach first child - switch(type) - { + switch(type) { case DTM.NAMESPACE_NODE: declareNamespaceInContext(parentIndex,nodeIndex); break; @@ -2376,8 +2317,7 @@ default: if (DTM.NULL != previousSibling) { m_nextsib.setElementAt(nodeIndex,previousSibling); - } - else if (DTM.NULL != parentIndex) { + } else if (DTM.NULL != parentIndex) { m_firstch.setElementAt(nodeIndex,parentIndex); } break; @@ -2390,16 +2330,12 @@ * Check whether accumulated text should be stripped; if not, * append the appropriate flavor of text/cdata node. */ - protected final void charactersFlush() - { - - if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress - { + protected final void charactersFlush() { + if (m_textPendingStart >= 0) { // -1 indicates no-text-in-progress int length = m_chars.size() - m_textPendingStart; boolean doStrip = false; - if (getShouldStripWhitespace()) - { + if (getShouldStripWhitespace()) { doStrip = m_chars.isWhitespace(m_textPendingStart, length); } @@ -2412,19 +2348,19 @@ // If the offset and length do not exceed the given limits // (offset < 2^21 and length < 2^10), then save both the offset // and length in a bitwise encoded value. - if (length <= TEXT_LENGTH_MAX - && m_textPendingStart <= TEXT_OFFSET_MAX) { + if (length <= TEXT_LENGTH_MAX && + m_textPendingStart <= TEXT_OFFSET_MAX) { m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE, - m_parents.peek(), m_previous, - length + (m_textPendingStart << TEXT_LENGTH_BITS), - false); + m_parents.peek(), m_previous, + length + (m_textPendingStart << TEXT_LENGTH_BITS), + false); } else { // Store offset and length in the m_data array if one exceeds // the given limits. Use a negative dataIndex as an indication. int dataIndex = m_data.size(); m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE, - m_parents.peek(), m_previous, -dataIndex, false); + m_parents.peek(), m_previous, -dataIndex, false); m_data.addElement(m_textPendingStart); m_data.addElement(length); @@ -2452,7 +2388,7 @@ * none is supplied. * @throws SAXException Any SAX exception, possibly * wrapping another exception. - * @see org.xml.sax.ContentHandler#processingInstruction + * @see ContentHandler#processingInstruction */ public void processingInstruction(String target, String data) throws SAXException @@ -2467,7 +2403,7 @@ -dataIndex, false); m_data.addElement(m_valuesOrPrefixes.stringToIndex(target)); - m_values.addElement(data); + m_values.add(data); m_data.addElement(m_valueIndex++); } @@ -2865,9 +2801,9 @@ } if (m_xstrf != null) - return m_xstrf.newstr((String)m_values.elementAt(dataIndex)); + return m_xstrf.newstr(m_values.get(dataIndex)); else - return new XMLStringDefault((String)m_values.elementAt(dataIndex)); + return new XMLStringDefault(m_values.get(dataIndex)); } } @@ -2966,7 +2902,7 @@ dataIndex = m_data.elementAt(dataIndex + 1); } - return (String)m_values.elementAt(dataIndex); + return m_values.get(dataIndex); } } @@ -3106,7 +3042,7 @@ dataIndex = m_data.elementAt(dataIndex + 1); } - String str = (String)m_values.elementAt(dataIndex); + String str = m_values.get(dataIndex); if(normalize) FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(), @@ -3160,7 +3096,7 @@ dataIndex = m_data.elementAt(dataIndex + 1); } - return (String)m_values.elementAt(dataIndex); + return m_values.get(dataIndex); } } @@ -3202,8 +3138,7 @@ if (uri.length() == 0) { handler.startElement(name); return name; - } - else { + } else { int qnameIndex = m_dataOrQName.elementAt(nodeID); if (qnameIndex == 0) { @@ -3223,14 +3158,12 @@ String prefix; if (prefixIndex > 0) { prefix = qName.substring(0, prefixIndex); - } - else { + } else { prefix = null; } handler.namespaceAfterStartElement(prefix, uri); return qName; } - } /** @@ -3285,7 +3218,7 @@ dataIndex = m_data.elementAt(dataIndex + 1); } - String nodeValue = (String)m_values.elementAt(dataIndex); + String nodeValue = m_values.get(dataIndex); handler.namespaceAfterStartElement(nodeName, nodeValue); @@ -3335,7 +3268,6 @@ } - /** * Copy an Attribute node to a SerializationHandler * @@ -3347,14 +3279,6 @@ SerializationHandler handler) throws SAXException { - /* - final String uri = getNamespaceName(node); - if (uri.length() != 0) { - final String prefix = getPrefix(node); - handler.namespaceAfterStartElement(prefix, uri); - } - handler.addAttribute(getNodeName(node), getNodeValue(node)); - */ final ExtendedType extType = m_extendedTypes[exptype]; final String uri = extType.getNamespace(); final String localName = extType.getLocalName(); @@ -3377,7 +3301,7 @@ } String nodeName = (prefix != null) ? qname : localName; - String nodeValue = (String)m_values.elementAt(valueIndex); + String nodeValue = m_values.get(valueIndex); handler.addAttribute(uri, localName, nodeName, "CDATA", nodeValue); } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/AltCatalog.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/AltCatalog.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/AltCatalog.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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 @@ } /** - * Returns the catalog attribute as an URI String. + * Returns the catalog attribute as a URI String. * @return The value of the catalog attribute */ String getCatalogId() { @@ -66,7 +66,7 @@ } /** - * Returns the catalog attribute as an URI. + * Returns the catalog attribute as a URI. * @return The value of the catalog attribute */ URI getCatalogURI() { diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/BaseEntry.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/BaseEntry.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/BaseEntry.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Objects; +import static javax.xml.catalog.CatalogMessages.ERR_INVALID_ARGUMENT; /** * Represents a general Catalog entry. @@ -210,13 +211,12 @@ * @param arg The name of the argument * @param uri The URI to be verified * @return The URI created from the specified uri - * @throws IllegalArgumentException if the specified uri is null, - * or an URL can not be created based on the specified base and uri + * @throws NullPointerException if the specified uri is null + * @throws IllegalArgumentException if a URL can not be created based on + * the specified base and uri */ URL verifyURI(String arg, URL base, String uri) { - if (uri == null) { - CatalogMessages.reportIAE(new Object[]{uri, arg}, null); - } + CatalogMessages.reportNPEOnNull(arg, uri); URL url = null; uri = Normalizer.normalizeURI(uri); @@ -228,32 +228,9 @@ url = new URL(uri); } } catch (MalformedURLException e) { - CatalogMessages.reportIAE(new Object[]{uri, arg}, e); + CatalogMessages.reportIAE(ERR_INVALID_ARGUMENT, + new Object[]{uri, arg}, e); } return url; } - - /** - * Construct an absolute URI from a relative one, using the current base - * URI. - * - * @param sysid The (possibly relative) system identifier - * @return The system identifier made absolute with respect to the current - * {@link #base}. - */ - protected String makeAbsolute(String sysid) { - URL local = null; - - sysid = Util.fixSlashes(sysid); - /** - * try { local = new URL(base, sysid); } catch (MalformedURLException e) - * { catalogManager.debug.message(1, "Malformed URL on system - * identifier", sysid); } - */ - if (local != null) { - return local.toString(); - } else { - return sysid; - } - } } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/Catalog.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/Catalog.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Catalog.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ *

    *
  • Locate the external resources with a public or system identifier; *
  • - *
  • Locate an alternate URI reference with an URI. + *
  • Locate an alternate URI reference with a URI. *
  • *
*

@@ -84,7 +84,7 @@ * * @param systemId the system identifier of the entity to be matched * - * @return an URI string if a mapping is found, or null otherwise + * @return a URI string if a mapping is found, or null otherwise */ public String matchSystem(String systemId); @@ -108,7 +108,7 @@ * * @param publicId the public identifier of the entity to be matched * @see CatalogFeatures.Feature - * @return an URI string if a mapping is found, or null otherwise + * @return a URI string if a mapping is found, or null otherwise */ public String matchPublic(String publicId); @@ -134,7 +134,7 @@ * * @param uri the URI reference of the entity to be matched * - * @return an URI string if a mapping is found, or null otherwise + * @return a URI string if a mapping is found, or null otherwise */ public String matchURI(String uri); diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,14 +56,14 @@ * * * FILES - * A semicolon-delimited list of catalog files. Relative file paths are - * considered relative to ${user.dir}. + * A semicolon-delimited list of URIs to locate the catalog files. + * The URIs must be absolute and have a URL protocol handler for the URI scheme. * * javax.xml.catalog.files * javax.xml.catalog.files * javax.xml.catalog.files * String - * File paths + * URIs * * Reads the first catalog as the current catalog; Loads others if no match * is found in the current catalog including delegate catalogs if any. @@ -170,7 +170,7 @@ * Properties set through the Catalog API override those that may have been set * by system properties and/or in {@code jaxp.properties}. In case of multiple * interfaces, the latest in a procedure shall take preference. For - * {@link Feature#FILES}, this means that the path(s) specified through the methods + * {@link Feature#FILES}, this means that the URI(s) specified through the methods * of the {@link CatalogManager} will override any that may have been entered * through the {@link Builder}. * @@ -188,7 +188,7 @@ * in the following sample code: *

{@code
                 CatalogFeatures f = CatalogFeatures.builder()
-                        .with(Feature.FILES, "catalog.xml")
+                        .with(Feature.FILES, "file:///etc/xml/catalog")
                         .with(Feature.PREFER, "public")
                         .with(Feature.DEFER, "true")
                         .with(Feature.RESOLVE, "ignore")
@@ -202,14 +202,14 @@
  * Schema Validation ({@link javax.xml.validation}), and XML Transformation
  * ({@link javax.xml.transform}). The features described above can be set through JAXP
  * factories or processors that define a setProperty or setAttribute interface.
- * For example, the following code snippet sets a path to a catalog file on a SAX
+ * For example, the following code snippet sets a URI to a catalog file on a SAX
  * parser through the {@code javax.xml.catalog.files} property:
  * 

*

{@code
  *      SAXParserFactory spf = SAXParserFactory.newInstance();
  *      spf.setFeature(XMLConstants.USE_CATALOG, true); [1]
  *      SAXParser parser = spf.newSAXParser();
- *      parser.setProperty(CatalogFeatures.Feature.FILES.getPropertyName(), "catalog.xml");
+ *      parser.setProperty(CatalogFeatures.Feature.FILES.getPropertyName(), "file:///etc/xml/catalog");
  * }
*

* [1] Note that this statement is not required since the default value of @@ -275,7 +275,7 @@ The following XInclude element: - can be resolved using an uri entry: + can be resolved using a URI entry: or @@ -291,7 +291,7 @@ - can be resolved using an uri entry: + can be resolved using a URI entry: or @@ -308,7 +308,7 @@ The following include element: - can be resolved using an uri entry: + can be resolved using a URI entry: or @@ -323,7 +323,7 @@ The following include element: - can be resolved using an uri entry: + can be resolved using a URI entry: or @@ -338,7 +338,7 @@ The document in the following element: - can be resolved using an uri entry: + can be resolved using a URI entry: or @@ -559,7 +559,7 @@ values = new String[Feature.values().length]; states = new State[Feature.values().length]; for (Feature cf : Feature.values()) { - setProperty(cf.ordinal(), State.DEFAULT, cf.defaultValue()); + setProperty(cf, State.DEFAULT, cf.defaultValue()); } //read system properties or jaxp.properties readSystemProperties(); @@ -571,52 +571,27 @@ */ private void setProperties(Builder builder) { builder.values.entrySet().stream().forEach((entry) -> { - setProperty(entry.getKey().ordinal(), State.APIPROPERTY, entry.getValue()); + setProperty(entry.getKey(), State.APIPROPERTY, entry.getValue()); }); } /** - * Sets the value of a property by its index, updates only if it shall override. + * Sets the value of a property, updates only if it shall override. * * @param index the index of the property * @param state the state of the property * @param value the value of the property * @throws IllegalArgumentException if the value is invalid */ - private void setProperty(int index, State state, String value) { + private void setProperty(Feature feature, State state, String value) { + int index = feature.ordinal(); if (value != null && value.length() != 0) { - if (index == Feature.PREFER.ordinal()) { - if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) { - CatalogMessages.reportIAE(new Object[]{value, Feature.PREFER.name()}, null); - } - } else if (index == Feature.DEFER.ordinal()) { - if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) { - CatalogMessages.reportIAE(new Object[]{value, Feature.DEFER.name()}, null); - } - } else if (index == Feature.RESOLVE.ordinal()) { - if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE) - && !value.equals(RESOLVE_IGNORE)) { - CatalogMessages.reportIAE(new Object[]{value, Feature.RESOLVE.name()}, null); - } - } else if (index == Feature.FILES.ordinal()) { - try { - String[] catalogFile = value.split(";[ ]*"); - for (String temp : catalogFile) { - if (Util.verifyAndGetURI(temp, null) == null) { - CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null); - } - } - }catch (MalformedURLException | URISyntaxException | IllegalArgumentException ex) { - CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, ex); - } + if (state != State.APIPROPERTY) { + Util.validateFeatureInput(feature, value); } if (states[index] == null || state.compareTo(states[index]) >= 0) { values[index] = value; states[index] = state; } - } else { - if (state == State.SYSTEMPROPERTY || state == State.JAXPDOTPROPERTIES) { - CatalogMessages.reportIAE(new Object[]{value, Feature.values()[index].name()}, null); - } } } @@ -639,13 +614,13 @@ if (cf.hasSystemProperty()) { String value = SecuritySupport.getSystemProperty(sysPropertyName); if (value != null && !value.equals("")) { - setProperty(cf.ordinal(), State.SYSTEMPROPERTY, value); + setProperty(cf, State.SYSTEMPROPERTY, value); return true; } value = SecuritySupport.readJAXPProperty(sysPropertyName); if (value != null && !value.equals("")) { - setProperty(cf.ordinal(), State.JAXPDOTPROPERTIES, value); + setProperty(cf, State.JAXPDOTPROPERTIES, value); return true; } } @@ -685,9 +660,7 @@ * property */ public Builder with(Feature feature, String value) { - if (value == null || value.length() == 0) { - CatalogMessages.reportIAE(new Object[]{value, feature.name()}, null); - } + Util.validateFeatureInput(feature, value); values.put(feature, value); return this; } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ /* A list of catalog entry files from the input, excluding the current catalog. - Paths in the List are normalized. + URIs in the List are verified during input validation or property retrieval. */ List inputFiles; @@ -86,43 +86,44 @@ SAXParser parser; /** - * Construct a Catalog with specified path. + * Construct a Catalog with specified URI. * - * @param file The path to a catalog file. + * @param uris the uri(s) to one or more catalogs * @throws CatalogException If an error happens while parsing the specified * catalog file. */ - public CatalogImpl(CatalogFeatures f, String... file) throws CatalogException { - this(null, f, file); + public CatalogImpl(CatalogFeatures f, URI... uris) throws CatalogException { + this(null, f, uris); } /** - * Construct a Catalog with specified path. + * Construct a Catalog with specified URI. * * @param parent The parent catalog - * @param file The path to a catalog file. + * @param uris the uri(s) to one or more catalogs * @throws CatalogException If an error happens while parsing the specified * catalog file. */ - public CatalogImpl(CatalogImpl parent, CatalogFeatures f, String... file) throws CatalogException { + public CatalogImpl(CatalogImpl parent, CatalogFeatures f, URI... uris) throws CatalogException { super(CatalogEntryType.CATALOG, parent); if (f == null) { throw new NullPointerException( formatMessage(CatalogMessages.ERR_NULL_ARGUMENT, new Object[]{"CatalogFeatures"})); } - if (file.length > 0) { - CatalogMessages.reportNPEOnNull("The path to the catalog file", file[0]); - } - init(f); //Path of catalog files - String[] catalogFile = file; - if (level == 0 && file.length == 0) { + String[] catalogFile = null; + if (level == 0 && uris.length == 0) { String files = features.get(Feature.FILES); if (files != null) { - catalogFile = files.split(";[ ]*"); + catalogFile = files.split(";"); + } + } else { + catalogFile = new String[uris.length]; + for (int i=0; i { - getCatalog(getSystemId(file)); + inputFiles.stream().forEach((uri) -> { + getCatalog(URI.create(uri)); }); } } @@ -454,12 +432,11 @@ } CatalogImpl c = null; - String path = uri.toASCIIString(); if (verifyCatalogFile(uri)) { - c = getLoadedCatalog(path); + c = getLoadedCatalog(uri.toASCIIString()); if (c == null) { - c = new CatalogImpl(this, features, path); + c = new CatalogImpl(this, features, uri); c.load(); } } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +24,7 @@ */ package javax.xml.catalog; +import java.net.URI; /** * The Catalog Manager manages the creation of XML Catalogs and Catalog Resolvers. @@ -39,30 +40,36 @@ /** * Creates a {@code Catalog} object using the specified feature settings and - * path to one or more catalog files. + * uri(s) to one or more catalog files. *

- * If {@code paths} is empty, system property {@code javax.xml.catalog.files} - * will be read to locate the initial list of catalog files. + * If {@code uris} is empty, system property {@code javax.xml.catalog.files}, + * as defined in {@link CatalogFeatures}, will be read to locate the initial + * list of catalog files. *

- * If more than one catalog files are specified through the paths argument or + * If multiple catalog files are specified through the {@code uris} argument or * {@code javax.xml.catalog.files} property, the first entry is considered * the main catalog, while others are treated as alternative catalogs after * those referenced by the {@code nextCatalog} elements in the main catalog. *

* As specified in * - * XML Catalogs, OASIS Standard V1.1, invalid path entries will be ignored. - * No error will be reported. In case all entries are invalid, the resolver - * will return as no mapping is found. + * XML Catalogs, OASIS Standard V1.1, if a catalog entry is invalid, it + * is ignored. In case all entries are invalid, the resulting Catalog object + * will contain no Catalog elements. Any matching operation using the Catalog + * will return null. * * @param features the catalog features - * @param paths path(s) to one or more catalogs. + * @param uris uri(s) to one or more catalogs. * * @return an instance of a {@code Catalog} + * @throws IllegalArgumentException if either the URIs are not absolute + * or do not have a URL protocol handler for the URI scheme * @throws CatalogException If an error occurs while parsing the catalog + * @throws SecurityException if access to the resource is denied by the security manager */ - public static Catalog catalog(CatalogFeatures features, String... paths) { - CatalogImpl catalog = new CatalogImpl(features, paths); + public static Catalog catalog(CatalogFeatures features, URI... uris) { + Util.validateUrisSyntax(uris); + CatalogImpl catalog = new CatalogImpl(features, uris); catalog.load(); return catalog; } @@ -80,30 +87,36 @@ /** * Creates an instance of a {@code CatalogResolver} using the specified feature - * settings and path to one or more catalog files. + * settings and uri(s) to one or more catalog files. *

- * If {@code paths} is empty, system property {@code javax.xml.catalog.files} - * will be read to locate the initial list of catalog files. + * If {@code uris} is empty, system property {@code javax.xml.catalog.files}, + * as defined in {@link CatalogFeatures}, will be read to locate the initial + * list of catalog files. *

- * If more than one catalog files are specified through the paths argument or + * If multiple catalog files are specified through the {@code uris} argument or * {@code javax.xml.catalog.files} property, the first entry is considered * the main catalog, while others are treated as alternative catalogs after * those referenced by the {@code nextCatalog} elements in the main catalog. *

* As specified in * - * XML Catalogs, OASIS Standard V1.1, invalid path entries will be ignored. - * No error will be reported. In case all entries are invalid, the resolver - * will return as no mapping is found. + * XML Catalogs, OASIS Standard V1.1, if a catalog entry is invalid, it + * is ignored. In case all entries are invalid, the resulting CatalogResolver + * object will contain no valid catalog. Any resolution operation using the + * resolver therefore will return as no mapping is found. See {@link CatalogResolver} + * for the behavior when no mapping is found. * * @param features the catalog features - * @param paths the path(s) to one or more catalogs + * @param uris the uri(s) to one or more catalogs * * @return an instance of a {@code CatalogResolver} + * @throws IllegalArgumentException if either the URIs are not absolute + * or do not have a URL protocol handler for the URI scheme * @throws CatalogException If an error occurs while parsing the catalog + * @throws SecurityException if access to the resource is denied by the security manager */ - public static CatalogResolver catalogResolver(CatalogFeatures features, String... paths) { - Catalog catalog = catalog(features, paths); + public static CatalogResolver catalogResolver(CatalogFeatures features, URI... uris) { + Catalog catalog = catalog(features, uris); return new CatalogResolverImpl(catalog); } } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,10 +24,11 @@ */ package javax.xml.catalog; -import jdk.xml.internal.SecuritySupport; +import java.net.URI; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; +import jdk.xml.internal.SecuritySupport; /** * Catalog Error messages @@ -38,6 +39,8 @@ public static final String ERR_INVALID_CATALOG = "InvalidCatalog"; public static final String ERR_INVALID_ENTRY_TYPE = "InvalidEntryType"; + public static final String ERR_URI_NOTABSOLUTE = "UriNotAbsolute"; + public static final String ERR_URI_NOTVALIDURL = "UriNotValidUrl"; public static final String ERR_INVALID_ARGUMENT = "InvalidArgument"; public static final String ERR_NULL_ARGUMENT = "NullArgument"; public static final String ERR_CIRCULAR_REFERENCE = "CircularReference"; @@ -120,7 +123,7 @@ * @param name the name of the argument * @param value the value of the argument */ - static void reportNPEOnNull(String name, String value) { + static void reportNPEOnNull(String name, Object value) { if (value == null) { throw new NullPointerException( formatMessage(ERR_NULL_ARGUMENT, new Object[]{name})); @@ -132,9 +135,9 @@ * @param arguments the arguments for formating the error message * @param cause the cause if any */ - static void reportIAE(Object[] arguments, Throwable cause) { + static void reportIAE(String key, Object[] arguments, Throwable cause) { throw new IllegalArgumentException( - formatMessage(ERR_INVALID_ARGUMENT, arguments), cause); + formatMessage(key, arguments), cause); } /** @@ -174,7 +177,7 @@ /** * Returns sanitized URI. - * @param uri an URI to be sanitized + * @param uri a URI to be sanitized */ static String sanitize(String uri) { if (uri == null) { diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.properties --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.properties Wed Jul 05 22:42:01 2017 +0200 @@ -31,6 +31,8 @@ CircularReference = Circular reference is not allowed: ''{0}''. #errors +UriNotAbsolute = The specified URI ''{0}'' is not absolute. +UriNotValidUrl = The specified URI ''{0}'' is not a valid URL. InvalidArgument = The specified argument ''{0}'' (case sensitive) for ''{1}'' is not valid. NullArgument = The argument ''{0}'' can not be null. InvalidPath = The path ''{0}'' is invalid. diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,10 +25,6 @@ package javax.xml.catalog; import java.io.StringReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Path; -import java.nio.file.Paths; import javax.xml.catalog.BaseEntry.CatalogEntryType; import javax.xml.parsers.SAXParser; import javax.xml.transform.Source; @@ -94,25 +90,6 @@ this.parser = parser; } - /** - * Returns when the specified path is valid. - * @param path a path - * @return true if the path is valid, false otherwise - */ - boolean isValidPath(String path) { - boolean valid = true; - try { - Path p = Paths.get(new URI(path)); - if (!p.toFile().exists()) { - valid = false; - } - } catch (URISyntaxException ex) { - valid = false; - } - - return valid; - } - @Override public void startElement(String namespaceURI, String localName, diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolver.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolver.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolver.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +47,7 @@ * {@link javax.xml.stream.XMLResolver} and {@link org.w3c.dom.ls.LSResourceResolver} * however, make no such distinction. * In consistent with the existing Java API, this CatalogResolver recognizes a - * system identifier as an URI and will search both {@code system} and {@code uri} + * system identifier as a URI and will search both {@code system} and {@code uri} * entries in a catalog in order to find a matching entry. *

* The search is started in the current catalog. If a match is found, @@ -137,9 +137,9 @@ * with the specified {@code href} attribute. The {@code href} attribute will * be used literally, with no attempt to be made absolute to the {@code base}. *

- * If the value is an URN, the {@code href} attribute is recognized as a + * If the value is a URN, the {@code href} attribute is recognized as a * {@code publicId}, and used to search {@code public} entries. - * If the value is an URI, it is taken as a {@code systemId}, and used to + * If the value is a URI, it is taken as a {@code systemId}, and used to * search both {@code system} and {@code uri} entries. * * @@ -219,7 +219,7 @@ * @param publicId the public identifier of the external entity being * referenced, or {@code null} if no public identifier was * supplied or if the resource is not an entity. - * @param systemId the system identifier, an URI reference of the + * @param systemId the system identifier, a URI reference of the * external resource being referenced * @param baseUri the absolute base URI, not used by the CatalogResolver * diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ systemId = Normalizer.normalizeURI(Util.getNotNullOrEmpty(systemId)); publicId = Normalizer.normalizePublicId(Normalizer.decodeURN(Util.getNotNullOrEmpty(publicId))); - //check whether systemId is an urn + //check whether systemId is a urn if (systemId != null && systemId.startsWith(Util.URN)) { systemId = Normalizer.decodeURN(systemId); if (publicId != null && !publicId.equals(systemId)) { @@ -123,7 +123,7 @@ return null; } - //check whether uri is an urn + //check whether uri is a urn if (uri != null && uri.startsWith(Util.URN)) { String publicId = Normalizer.decodeURN(uri); if (publicId != null) { @@ -131,7 +131,7 @@ } } - //if no match with a public id, continue search for an URI + //if no match with a public id, continue search for a URI if (result == null) { //remove fragment if any. int hashPos = uri.indexOf("#"); diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,8 +25,6 @@ package javax.xml.catalog; import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -217,7 +215,7 @@ * @param systemId The system identifier of the external entity being * referenced. * - * @return An URI string if a mapping is found, or null otherwise. + * @return a URI string if a mapping is found, or null otherwise. */ public String matchSystem(String systemId) { systemEntrySearched = true; @@ -285,7 +283,7 @@ * @param publicId The public identifier of the external entity being * referenced. * - * @return An URI string if a mapping is found, or null otherwise. + * @return a URI string if a mapping is found, or null otherwise. */ public String matchPublic(String publicId) { /* @@ -329,7 +327,7 @@ * * @param uri The URI reference of a resource. * - * @return An URI string if a mapping is found, or null otherwise. + * @return a URI string if a mapping is found, or null otherwise. */ public String matchURI(String uri) { String match = null; @@ -455,7 +453,7 @@ delegateCatalog = getLoadedCatalog(catalogId); if (delegateCatalog == null) { if (verifyCatalogFile(catalogURI)) { - delegateCatalog = new CatalogImpl(catalog, features, catalogId); + delegateCatalog = new CatalogImpl(catalog, features, catalogURI); delegateCatalog.load(); delegateCatalogs.put(catalogId, delegateCatalog); } @@ -504,7 +502,8 @@ } //Ignore it if it doesn't exist - if (!Files.exists(Paths.get(catalogURI))) { + if (Util.isFileUri(catalogURI) && + !Util.isFileUriExist(catalogURI, false)) { return false; } diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/UriEntry.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/UriEntry.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/UriEntry.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import java.net.URL; /** - * Represents an uriEntry entry. + * Represents a uri entry. * * @since 9 */ @@ -36,7 +36,7 @@ URL uri; /** - * Construct a group entry. + * Construct a uri entry. * @param name The name attribute. * @param uri The uri attribute. */ diff -r 047a57b0839a -r 1c9922f121ff jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,13 +25,20 @@ package javax.xml.catalog; import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Iterator; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import static javax.xml.catalog.CatalogFeatures.DEFER_FALSE; +import static javax.xml.catalog.CatalogFeatures.DEFER_TRUE; +import javax.xml.catalog.CatalogFeatures.Feature; +import static javax.xml.catalog.CatalogFeatures.PREFER_PUBLIC; +import static javax.xml.catalog.CatalogFeatures.PREFER_SYSTEM; +import static javax.xml.catalog.CatalogFeatures.RESOLVE_CONTINUE; +import static javax.xml.catalog.CatalogFeatures.RESOLVE_IGNORE; +import static javax.xml.catalog.CatalogFeatures.RESOLVE_STRICT; import jdk.xml.internal.SecuritySupport; /** @@ -39,22 +46,25 @@ * @since 9 */ class Util { + final static String URN = "urn:publicid:"; final static String PUBLICID_PREFIX = "-//"; final static String PUBLICID_PREFIX_ALT = "+//"; + final static String SCHEME_FILE = "file"; + final static String SCHEME_JAR = "jar"; + final static String SCHEME_JARFILE = "jar:file:"; /** * Finds an entry in the catalog that matches with the publicId or systemId. * - * The resolution follows the following rules determined by the prefer setting: + * The resolution follows the following rules determined by the prefer + * setting: * - * prefer "system": attempts to resolve with a system entry; - * attempts to resolve with a public entry when only - * publicId is specified. + * prefer "system": attempts to resolve with a system entry; attempts to + * resolve with a public entry when only publicId is specified. * - * prefer "public": attempts to resolve with a system entry; - * attempts to resolve with a public entry if no matching - * system entry is found. + * prefer "public": attempts to resolve with a system entry; attempts to + * resolve with a public entry if no matching system entry is found. * * If no match is found, continue searching uri entries * @@ -70,9 +80,9 @@ catalog.reset(); if (systemId != null) { /* - If a system identifier is specified, it is used no matter how - prefer is set. - */ + If a system identifier is specified, it is used no matter how + prefer is set. + */ resolvedSystemId = catalog.matchSystem(systemId); } @@ -91,7 +101,7 @@ if (resolvedSystemId == null) { Iterator iter = catalog.catalogs().iterator(); while (iter.hasNext()) { - resolvedSystemId = resolve((CatalogImpl)iter.next(), publicId, systemId); + resolvedSystemId = resolve((CatalogImpl) iter.next(), publicId, systemId); if (resolvedSystemId != null) { break; } @@ -102,73 +112,112 @@ return resolvedSystemId; } + static void validateUrisSyntax(URI... uris) { + for (URI uri : uris) { + validateUriSyntax(uri); + } + } + + static void validateUrisSyntax(String... uris) { + for (String uri : uris) { + validateUriSyntax(URI.create(uri)); + } + } + /** - * Resolves the specified file path to an absolute systemId. If it is - * relative, it shall be resolved using the base or user.dir property if - * base is not specified. + * Validate that the URI must be absolute and a valid URL. * - * @param file The specified file path - * @param baseURI the base URI - * @return The URI - * @throws CatalogException if the specified file path can not be converted - * to a system id + * Note that this method does not verify the existence of the resource. The + * Catalog standard requires that such resources be ignored. + * + * @param uri + * @throws IllegalArgumentException if the uri is not absolute and a valid + * URL */ - static URI verifyAndGetURI(String file, URL baseURI) - throws MalformedURLException, URISyntaxException, IllegalArgumentException { - URL filepath; - URI temp; - if (file != null && file.length() > 0) { - File f = new File(file); + static void validateUriSyntax(URI uri) { + CatalogMessages.reportNPEOnNull("URI input", uri); + + if (!uri.isAbsolute()) { + CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTABSOLUTE, + new Object[]{uri}, null); + } - if (baseURI != null && !f.isAbsolute()) { - filepath = new URL(baseURI, fixSlashes(file)); - temp = filepath.toURI(); - } else { - temp = resolveURI(file); - } - //Paths.get may throw IllegalArgumentException - Path path = Paths.get(temp); - if (path.toFile().isFile()) { - return temp; + try { + // check if the scheme was valid + uri.toURL(); + } catch (MalformedURLException ex) { + CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTVALIDURL, + new Object[]{uri}, null); + } + + // verify the resource exists where possible + if (isFileUri(uri)) { + if (!isFileUriExist(uri, false)) { + CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTVALIDURL, + new Object[]{uri}, null); } } - return null; } /** - * Resolves the specified uri. If the uri is relative, makes it absolute by - * the user.dir directory. + * Checks whether the URI is a file URI, including JAR file. * - * @param uri The specified URI. - * @return The resolved URI + * @param uri the specified URI. + * @return true if it is a file or JAR file URI, false otherwise */ - static URI resolveURI(String uri) throws MalformedURLException { - if (uri == null) { - uri = ""; + static boolean isFileUri(URI uri) { + if (SCHEME_FILE.equals(uri.getScheme()) + || SCHEME_JAR.equals(uri.getScheme())) { + return true; } - - URI temp = null; - try { - URL url = new URL(uri); - temp = url.toURI(); - } catch (MalformedURLException | URISyntaxException mue) { - File file = new File(uri); - temp = file.toURI(); - } - - return temp; + return false; } /** - * Replace backslashes with forward slashes. (URLs always use forward - * slashes.) + * Verifies whether the file resource exists. * - * @param sysid The input system identifier. - * @return The same system identifier with backslashes turned into forward - * slashes. + * @param uri the URI to locate the resource + * @param openJarFile a flag to indicate whether a JAR file should be + * opened. This operation may be expensive. + * @return true if the resource exists, false otherwise. */ - static String fixSlashes(String sysid) { - return sysid.replace('\\', '/'); + static boolean isFileUriExist(URI uri, boolean openJarFile) { + if (uri != null && uri.isAbsolute()) { + if (null != uri.getScheme()) { + switch (uri.getScheme()) { + case SCHEME_FILE: + String path = uri.getPath(); + File f1 = new File(path); + if (f1.isFile()) { + return true; + } + break; + case SCHEME_JAR: + String tempUri = uri.toString(); + int pos = tempUri.indexOf("!"); + if (pos < 0) { + return false; + } + if (openJarFile) { + String jarFile = tempUri.substring(SCHEME_JARFILE.length(), pos); + String entryName = tempUri.substring(pos + 2); + try { + JarFile jf = new JarFile(jarFile); + JarEntry je = jf.getJarEntry(entryName); + if (je != null) { + return true; + } + } catch (IOException ex) { + return false; + } + } else { + return true; + } + break; + } + } + } + return false; } /** @@ -187,11 +236,12 @@ } /** - * Checks whether the specified string is null or empty, returns the original - * string with leading and trailing spaces removed if not. + * Checks whether the specified string is null or empty, returns the + * original string with leading and trailing spaces removed if not. + * * @param test the string to be tested - * @return the original string with leading and trailing spaces removed, - * or null if it is null or empty + * @return the original string with leading and trailing spaces removed, or + * null if it is null or empty * */ static String getNotNullOrEmpty(String test) { @@ -206,4 +256,39 @@ } } } + + /** + * Validates the input for features. + * + * @param f the feature + * @param value the value + * @throws IllegalArgumentException if the value is invalid for the feature + */ + static void validateFeatureInput(Feature f, String value) { + CatalogMessages.reportNPEOnNull(f.name(), value); + if (value.length() == 0) { + CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, + new Object[]{value, f.name()}, null); + } + + if (f == Feature.PREFER) { + if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) { + CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, + new Object[]{value, Feature.PREFER.name()}, null); + } + } else if (f == Feature.DEFER) { + if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) { + CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, + new Object[]{value, Feature.DEFER.name()}, null); + } + } else if (f == Feature.RESOLVE) { + if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE) + && !value.equals(RESOLVE_IGNORE)) { + CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, + new Object[]{value, Feature.RESOLVE.name()}, null); + } + } else if (f == Feature.FILES) { + Util.validateUrisSyntax(value.split(";")); + } + } } diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/functional/catalog/SpecifyCatalogTest.java --- a/jaxp/test/javax/xml/jaxp/functional/catalog/SpecifyCatalogTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/test/javax/xml/jaxp/functional/catalog/SpecifyCatalogTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ @Test public void specifyCatalogViaSysProps() { setSystemProperty(FEATURE_FILES, - getCatalogPath("specifyCatalog-sysProps.xml")); + getCatalogPath("specifyCatalog-sysProps.xml").toASCIIString()); checkResolutionOnEntityResolver(catalogResolver((String[]) null), "http://local/base/dtd/docSysPropsSys.dtd"); @@ -107,6 +107,6 @@ } private static CatalogFeatures createFeature(String catalogName) { - return builder().with(FILES, getCatalogPath(catalogName)).build(); + return builder().with(FILES, getCatalogPath(catalogName).toASCIIString()).build(); } } diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/dummy.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/dummy.xml Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,1 @@ + diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java --- a/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,17 +25,16 @@ import java.io.File; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; - import javax.xml.catalog.CatalogFeatures; import javax.xml.catalog.CatalogManager; import javax.xml.catalog.CatalogResolver; - import jaxp.library.JAXPTestUtilities; /* @@ -115,20 +114,20 @@ } // Gets the paths of the specified catalogs. - private static String[] getCatalogPaths(String... catalogNames) { + private static URI[] getCatalogPaths(String... catalogNames) { return catalogNames == null ? null : Stream.of(catalogNames).map( catalogName -> getCatalogPath(catalogName)).collect( - Collectors.toList()).toArray(new String[0]); + Collectors.toList()).toArray(new URI[0]); } // Gets the paths of the specified catalogs. - static String getCatalogPath(String catalogName) { + static URI getCatalogPath(String catalogName) { return catalogName == null ? null - : JAXPTestUtilities.getPathByClassName(CatalogTestUtils.class, "catalogFiles") - + catalogName; + : Paths.get(JAXPTestUtilities.getPathByClassName(CatalogTestUtils.class, "catalogFiles") + + catalogName).toUri(); } /* ********** jaxp.properties ********** */ diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/libs/jaxp/library/JarUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JarUtils.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jaxp.library; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * This class consists exclusively of static utility methods that are useful + * for creating and manipulating JAR files. + */ + +public final class JarUtils { + private JarUtils() { } + + /** + * Creates a JAR file. + * + * Equivalent to {@code jar cfm -C

file...} + * + * The input files are resolved against the given directory. Any input + * files that are directories are processed recursively. + */ + public static void createJarFile(Path jarfile, Manifest man, Path dir, Path... file) + throws IOException + { + // create the target directory + Path parent = jarfile.getParent(); + if (parent != null) + Files.createDirectories(parent); + + List entries = new ArrayList<>(); + for (Path entry : file) { + Files.find(dir.resolve(entry), Integer.MAX_VALUE, + (p, attrs) -> attrs.isRegularFile()) + .map(e -> dir.relativize(e)) + .forEach(entries::add); + } + + try (OutputStream out = Files.newOutputStream(jarfile); + JarOutputStream jos = new JarOutputStream(out)) + { + if (man != null) { + JarEntry je = new JarEntry(JarFile.MANIFEST_NAME); + jos.putNextEntry(je); + man.write(jos); + jos.closeEntry(); + } + + for (Path entry : entries) { + String name = toJarEntryName(entry); + jos.putNextEntry(new JarEntry(name)); + Files.copy(dir.resolve(entry), jos); + jos.closeEntry(); + } + } + } + + /** + * Creates a JAR file. + * + * Equivalent to {@code jar cf -C file...} + * + * The input files are resolved against the given directory. Any input + * files that are directories are processed recursively. + */ + public static void createJarFile(Path jarfile, Path dir, Path... file) + throws IOException + { + createJarFile(jarfile, null, dir, file); + } + + /** + * Creates a JAR file. + * + * Equivalent to {@code jar cf -C file...} + * + * The input files are resolved against the given directory. Any input + * files that are directories are processed recursively. + */ + public static void createJarFile(Path jarfile, Path dir, String... input) + throws IOException + { + Path[] paths = Stream.of(input).map(Paths::get).toArray(Path[]::new); + createJarFile(jarfile, dir, paths); + } + + /** + * Creates a JAR file from the contents of a directory. + * + * Equivalent to {@code jar cf -C .} + */ + public static void createJarFile(Path jarfile, Path dir) throws IOException { + createJarFile(jarfile, dir, Paths.get(".")); + } + + /** + * Map a file path to the equivalent name in a JAR file + */ + private static String toJarEntryName(Path file) { + Path normalized = file.normalize(); + return normalized.subpath(0, normalized.getNameCount()) // drop root + .toString() + .replace(File.separatorChar, '/'); + } +} diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/libs/jaxp/library/SimpleHttpServer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/SimpleHttpServer.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jaxp.library; + +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 java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * A simple HTTP Server + */ +public class SimpleHttpServer { + HttpServer _httpserver; + ExecutorService _executor; + + String _address; + + String _context, _docroot; + int _port; + + public SimpleHttpServer(String context, String docroot) { + //let the system pick up an ephemeral port in a bind operation + this(0, context, docroot); + } + + public SimpleHttpServer(int port, String context, String docroot) { + _port = port; + _context = context; + _docroot = docroot; + } + + public void start() { + MyHttpHandler handler = new MyHttpHandler(_docroot); + InetSocketAddress addr = new InetSocketAddress(_port); + try { + _httpserver = HttpServer.create(addr, 0); + } catch (IOException ex) { + throw new RuntimeException("cannot create httpserver", ex); + } + + //TestHandler is mapped to /test + HttpContext ctx = _httpserver.createContext(_context, handler); + + _executor = Executors.newCachedThreadPool(); + _httpserver.setExecutor(_executor); + _httpserver.start(); + + _address = "http://localhost:" + _httpserver.getAddress().getPort(); + } + + public void stop() { + _httpserver.stop(2); + _executor.shutdown(); + } + + public String getAddress() { + return _address; + } + + static class MyHttpHandler implements HttpHandler { + + String _docroot; + + public MyHttpHandler(String docroot) { + _docroot = docroot; + } + + public void handle(HttpExchange t) + throws IOException { + InputStream is = t.getRequestBody(); + Headers map = t.getRequestHeaders(); + Headers rmap = t.getResponseHeaders(); + OutputStream os = t.getResponseBody(); + URI uri = t.getRequestURI(); + String path = uri.getPath(); + + + while (is.read() != -1) ; + is.close(); + + File f = new File(_docroot, path); + if (!f.exists()) { + notfound(t, path); + return; + } + + String method = t.getRequestMethod(); + if (method.equals("HEAD")) { + rmap.set("Content-Length", Long.toString(f.length())); + t.sendResponseHeaders(200, -1); + t.close(); + } else if (!method.equals("GET")) { + t.sendResponseHeaders(405, -1); + t.close(); + return; + } + + if (path.endsWith(".html") || path.endsWith(".htm")) { + rmap.set("Content-Type", "text/html"); + } else { + rmap.set("Content-Type", "text/plain"); + } + + t.sendResponseHeaders (200, f.length()); + + FileInputStream fis = new FileInputStream(f); + int count = 0; + try { + byte[] buf = new byte[16 * 1024]; + int len; + while ((len = fis.read(buf)) != -1) { + os.write(buf, 0, len); + count += len; + } + } catch (IOException e) { + e.printStackTrace(); + } + fis.close(); + os.close(); + } + + void moved(HttpExchange t) throws IOException { + Headers req = t.getRequestHeaders(); + Headers map = t.getResponseHeaders(); + URI uri = t.getRequestURI(); + String host = req.getFirst("Host"); + String location = "http://" + host + uri.getPath() + "/"; + map.set("Content-Type", "text/html"); + map.set("Location", location); + t.sendResponseHeaders(301, -1); + t.close(); + } + + void notfound(HttpExchange t, String p) throws IOException { + t.getResponseHeaders().set("Content-Type", "text/html"); + t.sendResponseHeaders(404, 0); + OutputStream os = t.getResponseBody(); + String s = "

File not found

"; + s = s + p + "

"; + os.write(s.getBytes()); + os.close(); + t.close(); + } + } + +} diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogAccessTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogAccessTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 java.net.URI; +import javax.xml.catalog.CatalogFeatures; +import javax.xml.catalog.CatalogManager; +import javax.xml.catalog.CatalogResolver; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; +import org.xml.sax.InputSource; +import static jaxp.library.JAXPTestUtilities.tryRunWithAllPerm; + +/* + * @test + * @bug 8171243 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng/othervm -DrunSecMngr=true catalog.CatalogAccessTest + * @summary the Catalog API grants no privilege to external resources. This test + * verifies that SecurityException will be thrown if access to resources is denied + * by the security manager. + */ +@Listeners({jaxp.library.BasePolicy.class}) +public class CatalogAccessTest { + static final CatalogFeatures FEATURES = CatalogFeatures.builder(). + with(CatalogFeatures.Feature.PREFER, "system").build(); + + /* + * Verifies that the SecurityException is thrown if access to the resource is + * denied by the security manager. + */ + @Test(dataProvider = "accessTest", expectedExceptions = SecurityException.class) + public void testSecurity(String cfile, String sysId, String pubId) throws Exception { + CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, URI.create(cfile)); + InputSource is = cr.resolveEntity(pubId, sysId); + Assert.fail("Failed to throw SecurityException"); + } + + /* + DataProvider: used for SecurityException testing + Data columns: + catalog uri, systemId, publicId + */ + @DataProvider(name = "accessTest") + Object[][] getDataForAccessTest() throws Exception { + String systemId = "http://www.sys00test.com/rewrite.dtd"; + String publicId = "PUB-404"; + String urlFile = tryRunWithAllPerm(() -> + getClass().getResource("rewriteSystem_id.xml").toExternalForm()); + return new Object[][]{ + {urlFile, systemId, publicId} + }; + } +} diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import static java.nio.file.StandardOpenOption.APPEND; +import static java.nio.file.StandardOpenOption.CREATE; +import javax.xml.catalog.Catalog; +import javax.xml.catalog.CatalogException; +import javax.xml.catalog.CatalogFeatures; +import javax.xml.catalog.CatalogManager; +import javax.xml.catalog.CatalogResolver; +import static jaxp.library.JAXPTestUtilities.getSystemProperty; +import jaxp.library.JarUtils; +import jaxp.library.SimpleHttpServer; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; +import org.xml.sax.InputSource; + +/* + * @test + * @bug 8151154 8171243 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng/othervm catalog.CatalogFileInputTest + * @summary Verifies that the Catalog API accepts valid URIs only; + 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. + */ +@Listeners({jaxp.library.FilePolicy.class, jaxp.library.NetAccessPolicy.class}) +public class CatalogFileInputTest extends CatalogSupportBase { + + static final CatalogFeatures FEATURES = CatalogFeatures.builder(). + with(CatalogFeatures.Feature.PREFER, "system").build(); + static String USER_DIR = getSystemProperty("user.dir"); + static String CLS_DIR = getSystemProperty("test.classes"); + static String SRC_DIR = System.getProperty("test.src"); + static String JAR_CONTENT = "META-INF"; + final static String SCHEME_JARFILE = "jar:"; + static final String REMOTE_FILE_LOCATION = "/jar/META-INF"; + static final String DOCROOT = SRC_DIR; + static final String TESTCONTEXT = REMOTE_FILE_LOCATION; //mapped to local file path + SimpleHttpServer _httpserver; + String _remoteFilePath; + + /* + * Initializing fields + */ + @BeforeClass + public void setUpClass() throws Exception { + super.setUp(); + + // set up HttpServer + _httpserver = new SimpleHttpServer(TESTCONTEXT, DOCROOT); + _httpserver.start(); + _remoteFilePath = _httpserver.getAddress() + REMOTE_FILE_LOCATION; + + } + + @AfterClass + protected void tearDown() throws Exception { + if (_httpserver != null) { + _httpserver.stop(); + } + } + + /* + * Verifies that the Catalog can be created with file system paths including JAR + * and http URL, and used to resolve a systemId as expected. + */ + @Test(dataProvider = "acceptedURI") + public void testMatch(String uri, String sysId, String pubId, + String expectedId, String msg) throws Exception { + CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, URI.create(uri)); + InputSource is = cr.resolveEntity(pubId, sysId); + Assert.assertNotNull(is, msg); + Assert.assertEquals(expectedId, is.getSystemId(), msg); + } + + @Test(dataProvider = "invalidCatalog") + public void testEmptyCatalog(String uri, String publicId, String msg) { + Catalog c = CatalogManager.catalog(FEATURES, uri != null? URI.create(uri) : null); + Assert.assertNull(c.matchSystem(publicId), msg); + } + + @Test(dataProvider = "invalidCatalog", expectedExceptions = CatalogException.class) + public void testCatalogResolverWEmptyCatalog(String uri, String publicId, String msg) { + CatalogResolver cr = CatalogManager.catalogResolver( + CatalogFeatures.builder().with(CatalogFeatures.Feature.RESOLVE, "strict").build(), + uri != null? URI.create(uri) : null); + InputSource is = cr.resolveEntity(publicId, ""); + } + + @Test(dataProvider = "invalidCatalog") + public void testCatalogResolverWEmptyCatalog1(String uri, String publicId, String msg) { + CatalogResolver cr = CatalogManager.catalogResolver( + CatalogFeatures.builder().with(CatalogFeatures.Feature.RESOLVE, "continue").build(), + uri != null? URI.create(uri) : null); + Assert.assertNull(cr.resolveEntity(publicId, ""), msg); + } + + @Test(dataProvider = "invalidInput", expectedExceptions = IllegalArgumentException.class) + public void testFileInput(String file) { + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.FILES, file) + .build(); + } + + @Test(dataProvider = "invalidInput", expectedExceptions = IllegalArgumentException.class) + public void testInvalidUri(String file) { + CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, file != null? URI.create(file) : null); + } + + @Test(dataProvider = "invalidInput", expectedExceptions = IllegalArgumentException.class) + public void testInvalidUri1(String file) { + Catalog c = CatalogManager.catalog(FEATURES, file != null? URI.create(file) : null); + System.err.println("Catalog =" + c); + } + + + @Test(expectedExceptions = NullPointerException.class) + public void testNullFileInput() { + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.FILES, null) + .build(); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullUri() { + URI uri = null; + CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, uri); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullUri1() { + URI uri = null; + Catalog c = CatalogManager.catalog(FEATURES, uri); + } + + String systemId = "http://www.sys00test.com/rewrite.dtd"; + String publicId = "PUB-404"; + String expected = "http://www.groupxmlbase.com/dtds/rewrite.dtd"; + String errMsg = "Relative rewriteSystem with xml:base at group level failed"; + + /* + DataProvider: used to verify CatalogResolver's resolveEntity function. + Data columns: + catalog, systemId, publicId, expectedUri, msg + */ + @DataProvider(name = "acceptedURI") + Object[][] getData() throws Exception { + String filename = "rewriteSystem_id.xml"; + String urlFile = getClass().getResource(filename).toExternalForm(); + String urlHttp = _remoteFilePath + "/jax-ws-catalog.xml"; + String remoteXSD = _remoteFilePath + "/catalog/ws-addr.xsd"; + File file = new File(CLS_DIR + "/JDK8171243.jar!/META-INF/jax-ws-catalog.xml"); + String jarPath = SCHEME_JARFILE + file.toURI().toString(); + String xsd = jarPath.substring(0, jarPath.lastIndexOf("/")) + "/catalog/ws-addr.xsd"; + + // create JAR file + try { + JarUtils.createJarFile(Paths.get(CLS_DIR + "/JDK8171243.jar"), + Paths.get(SRC_DIR + "/jar"), JAR_CONTENT); + } catch (IOException ex) { + Assert.fail("Failed to create JAR: " + ex.getMessage()); + } + + return new Object[][]{ + // URL + {urlFile, systemId, publicId, expected, errMsg}, + {urlHttp, "http://www.w3.org/2006/03/addressing/ws-addr.xsd", "", remoteXSD, "http test failed."}, + // JAR file + {jarPath, "http://www.w3.org/2006/03/addressing/ws-addr.xsd", "", xsd, "jar file test failed."}, + }; + } + + /* + * DataProvider: invalid catalog result in empty catalog + * Note: the difference from invalidInput is that invalidInput is syntactically + * rejected with an IAE. + */ + @DataProvider(name = "invalidCatalog") + public Object[][] getInvalidCatalog() throws Exception { + String catalogUri = getClass().getResource("catalog_invalid.xml").toExternalForm(); + return new Object[][]{ + {catalogUri, "-//W3C//DTD XHTML 1.0 Strict//EN", + "The catalog is invalid, attempting to match the public entry shall return null."} + }; + } + + /* + * DataProvider: a list of invalid inputs, expects IAE + * Note: exclude null since NPE would have been expected + */ + @DataProvider(name = "invalidInput") + public Object[][] getFiles() throws Exception { + String filename = "rewriteSystem_id.xml"; + copyFile(Paths.get(SRC_DIR + "/" + filename), Paths.get(filename)); + String absolutePath = getClass().getResource(filename).getFile(); + + return new Object[][]{ + {""}, + {"file:a/b\\c"}, + {"file:/../../.."}, + {"c:/te:t"}, + {"c:/te?t"}, + {"c/te*t"}, + {"in|valid.txt"}, + {"shema:invalid.txt"}, + // relative file path + {filename}, + // absolute file path + {absolutePath} + }; + } + + /* + DataProvider: a list of invalid inputs + */ + @DataProvider(name = "nullTest") + public Object[][] getNull() throws Exception { + + return new Object[][]{ + {null}, + }; + } + + void copyFile(Path src, Path target) throws Exception { + + try (InputStream in = Files.newInputStream(src); + BufferedReader reader + = new BufferedReader(new InputStreamReader(in)); + OutputStream out = new BufferedOutputStream( + Files.newOutputStream(target, CREATE, APPEND)); + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out))) { + String line = null; + while ((line = reader.readLine()) != null) { + bw.write(line); + } + } catch (IOException x) { + throw new Exception(x.getMessage()); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package catalog; - -import javax.xml.catalog.CatalogFeatures; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -/* - * @test - * @bug 8151154 - * @run testng/othervm catalog.CatalogInvalidPathTest - * @summary Verifies that the CatalogFeatures' builder throws - * IllegalArgumentException on invalid file inputs. - * This test was splitted from CatalogTest.java due to - * JDK-8168968, it has to only run without SecurityManager - * because an ACE will be thrown for invalid path. - */ -public class CatalogInvalidPathTest { - /* - DataProvider: for testing the verification of file paths by - the CatalogFeatures builder - */ - @DataProvider(name = "invalidPaths") - public Object[][] getFiles() { - return new Object[][]{ - {null}, - {""}, - {"file:a/b\\c"}, - {"file:/../../.."}, - {"c:/te:t"}, - {"c:/te?t"}, - {"c/te*t"}, - {"in|valid.txt"}, - {"shema:invalid.txt"}, - }; - } - - @Test(dataProvider = "invalidPaths", expectedExceptions = IllegalArgumentException.class) - public void testFileInput(String file) { - CatalogFeatures features = CatalogFeatures.builder() - .with(CatalogFeatures.Feature.FILES, file) - .build(); - } -} diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +35,13 @@ import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; +import java.nio.file.Paths; +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 javax.xml.XMLConstants; import javax.xml.catalog.CatalogFeatures; import javax.xml.catalog.CatalogResolver; @@ -133,8 +140,8 @@ dtd_system = filepath + "system.dtd"; dtd_systemResolved = ""; - xml_catalog = filepath + "CatalogSupport.xml"; - xml_bogus_catalog = filepath + "CatalogSupport_bogus.xml"; + xml_catalog = Paths.get(filepath + "CatalogSupport.xml").toUri().toASCIIString(); + xml_bogus_catalog = Paths.get(filepath + "CatalogSupport_bogus.xml").toUri().toASCIIString(); xml_xInclude = "\n" + " 0) { result = c.matchPublic(publicId); @@ -430,8 +434,9 @@ * system entry is found. */ @Test(dataProvider = "resolveWithPrefer") - public void resolveWithPrefer(String prefer, String cfile, String publicId, String systemId, String expected) { - String catalogFile = getClass().getResource(cfile).getFile(); + public void resolveWithPrefer(String prefer, String cfile, String publicId, + String systemId, String expected) throws Exception { + URI catalogFile = getClass().getResource(cfile).toURI(); CatalogFeatures f = CatalogFeatures.builder().with(CatalogFeatures.Feature.PREFER, prefer).with(CatalogFeatures.Feature.RESOLVE, "ignore").build(); CatalogResolver catalogResolver = CatalogManager.catalogResolver(f, catalogFile); String result = catalogResolver.resolveEntity(publicId, systemId).getSystemId(); @@ -445,8 +450,8 @@ * be loaded is determined by the defer attribute. */ @Test(dataProvider = "invalidAltCatalogs", expectedExceptions = CatalogException.class) - public void testDeferAltCatalogs(String file) { - String catalogFile = getClass().getResource(file).getFile(); + public void testDeferAltCatalogs(String file) throws Exception { + URI catalogFile = getClass().getResource(file).toURI(); CatalogFeatures features = CatalogFeatures.builder().with(CatalogFeatures.Feature.DEFER, "true").build(); /* Since the defer attribute is set to false in the specified catalog file, @@ -462,8 +467,8 @@ * PREFER from Features API taking precedence over catalog file */ @Test - public void testJDK8146237() { - String catalogFile = getClass().getResource("JDK8146237_catalog.xml").getFile(); + public void testJDK8146237() throws Exception { + URI catalogFile = getClass().getResource("JDK8146237_catalog.xml").toURI(); try { CatalogFeatures features = CatalogFeatures.builder().with(CatalogFeatures.Feature.PREFER, "system").build(); @@ -482,8 +487,8 @@ Verifies that the resulting systemId does not contain duplicate slashes */ @Test - public void testRewriteSystem() { - String catalog = getClass().getResource("rewriteCatalog.xml").getFile(); + public void testRewriteSystem() throws Exception { + URI catalog = getClass().getResource("rewriteCatalog.xml").toURI(); try { CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); @@ -500,8 +505,8 @@ Verifies that the resulting systemId does not contain duplicate slashes */ @Test - public void testRewriteUri() { - String catalog = getClass().getResource("rewriteCatalog.xml").getFile(); + public void testRewriteUri() throws Exception { + URI catalog = getClass().getResource("rewriteCatalog.xml").toURI(); try { @@ -519,18 +524,18 @@ */ @Test(expectedExceptions = NullPointerException.class) public void testFeatureNull() { - CatalogResolver resolver = CatalogManager.catalogResolver(null, ""); + CatalogResolver resolver = CatalogManager.catalogResolver(null, null); } /* @bug 8144966 - Verifies that passing null as the path will result in a NPE. + Verifies that passing null as the URI will result in a NPE. */ @Test(expectedExceptions = NullPointerException.class) public void testPathNull() { - String path = null; - CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), path); + URI uri = null; + CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), uri); } /* @@ -540,10 +545,11 @@ that matches the expected value. */ @Test(dataProvider = "catalog") - public void testCatalogResolver(String test, String expected, String catalogFile, String xml, SAXParser saxParser) { - String catalog = null; + public void testCatalogResolver(String test, String expected, String catalogFile, + String xml, SAXParser saxParser) throws Exception { + URI catalog = null; if (catalogFile != null) { - catalog = getClass().getResource(catalogFile).getFile(); + catalog = getClass().getResource(catalogFile).toURI(); } String url = getClass().getResource(xml).getFile(); try { @@ -565,8 +571,8 @@ catalog is provided, the resolver will throw an exception by default. */ @Test - public void testInvalidCatalog() { - String catalog = getClass().getResource("catalog_invalid.xml").getFile(); + public void testInvalidCatalog() throws Exception { + URI catalog = getClass().getResource("catalog_invalid.xml").toURI(); String test = "testInvalidCatalog"; try { @@ -590,7 +596,7 @@ */ @Test public void testIgnoreInvalidCatalog() { - String catalog = getClass().getResource("catalog_invalid.xml").getFile(); + String catalog = getClass().getResource("catalog_invalid.xml").toExternalForm(); CatalogFeatures f = CatalogFeatures.builder() .with(Feature.FILES, catalog) .with(Feature.PREFER, "public") @@ -600,7 +606,7 @@ String test = "testInvalidCatalog"; try { - CatalogResolver resolver = CatalogManager.catalogResolver(f, ""); + CatalogResolver resolver = CatalogManager.catalogResolver(f); String actualSystemId = resolver.resolveEntity(null, "http://remote/xml/dtd/sys/alice/docAlice.dtd").getSystemId(); System.out.println("testIgnoreInvalidCatalog: expected [null]"); System.out.println("testIgnoreInvalidCatalog: expected [null]"); diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/jar/META-INF/MANIFEST.MF --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/jar/META-INF/MANIFEST.MF Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Created-By: 9-ea (Oracle Corporation) + diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/jar/META-INF/catalog/ws-addr.xsd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/jar/META-INF/catalog/ws-addr.xsd Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/catalog/jar/META-INF/jax-ws-catalog.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/jar/META-INF/jax-ws-catalog.xml Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff -r 047a57b0839a -r 1c9922f121ff jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java --- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -37,6 +37,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; @@ -74,11 +75,30 @@ * @run testng/othervm -DrunSecMngr=true transform.TransformerTest * @run testng/othervm transform.TransformerTest * @summary Transformer Tests - * @bug 6272879 6305029 6505031 8150704 8162598 8169112 8169772 + * @bug 6272879 6305029 6505031 8150704 8162598 8169112 8169631 8169772 */ @Listeners({jaxp.library.FilePolicy.class}) public class TransformerTest { + // some global constants + private static final String LINE_SEPARATOR = + getSystemProperty("line.separator"); + + private static final String NAMESPACES = + "http://xml.org/sax/features/namespaces"; + + private static final String NAMESPACE_PREFIXES = + "http://xml.org/sax/features/namespace-prefixes"; + + private static abstract class TestTemplate { + protected void printSnippet(String title, String snippet) { + StringBuilder div = new StringBuilder(); + for (int i = 0; i < title.length(); i++) + div.append("="); + System.out.println(title + "\n" + div + "\n" + snippet + "\n"); + } + } + /** * Reads the contents of the given file into a string. * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one. @@ -101,44 +121,7 @@ } } - /** - * Utility method for testBug8162598(). - * Provides a convenient way to check/assert the expected namespaces - * of a Node and its siblings. - * - * @param test - * The node to check - * @param nstest - * Expected namespace of the node - * @param nsb - * Expected namespace of the first sibling - * @param nsc - * Expected namespace of the first sibling of the first sibling - */ - private void checkNodeNS8162598(Node test, String nstest, String nsb, String nsc) { - String testNodeName = test.getNodeName(); - if (nstest == null) { - Assert.assertNull(test.getNamespaceURI(), "unexpected namespace for " + testNodeName); - } else { - Assert.assertEquals(test.getNamespaceURI(), nstest, "unexpected namespace for " + testNodeName); - } - Node b = test.getChildNodes().item(0); - if (nsb == null) { - Assert.assertNull(b.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b"); - } else { - Assert.assertEquals(b.getNamespaceURI(), nsb, "unexpected namespace for " + testNodeName + "->b"); - } - Node c = b.getChildNodes().item(0); - if (nsc == null) { - Assert.assertNull(c.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b->c"); - } else { - Assert.assertEquals(c.getNamespaceURI(), nsc, "unexpected namespace for " + testNodeName + "->b->c"); - } - } - private class XMLReaderFor6305029 implements XMLReader { - private static final String NAMESPACES = "http://xml.org/sax/features/namespaces"; - private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; private boolean namespaces = true; private boolean namespacePrefixes = false; private EntityResolver resolver; @@ -235,8 +218,6 @@ */ @Test public final void testBug6272879() throws IOException, TransformerException { - final String LINE_SEPARATOR = getSystemProperty("line.separator"); - final String xsl = "" + LINE_SEPARATOR + "" + LINE_SEPARATOR + @@ -349,9 +330,125 @@ Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); } + private static class Test8169631 extends TestTemplate { + private final static String xsl = + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + "" + LINE_SEPARATOR; + + private final static String sourceXml = + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + " 1" + LINE_SEPARATOR + + " 2" + LINE_SEPARATOR + + " 3" + LINE_SEPARATOR + + "" + LINE_SEPARATOR; + + /** + * Utility method to print out transformation result and check values. + * + * @param type + * Text describing type of transformation + * @param result + * Resulting output of transformation + * @param elementCount + * Counter of elements to check + * @param attribCount + * Counter of attributes to check + */ + private void verifyResult(String type, String result, int elementCount, + int attribCount) + { + printSnippet("Result of transformation from " + type + ":", + result); + Assert.assertEquals( + result.contains("" + elementCount + ""), + true, "Result of transformation from " + type + + " should have count of " + elementCount + " elements."); + Assert.assertEquals( + result.contains("" + attribCount + + ""), true, "Result of transformation from " + + type + " should have count of "+ attribCount + " attributes."); + } + + public void run() throws IOException, TransformerException, + SAXException, ParserConfigurationException + { + printSnippet("Source:", sourceXml); + + printSnippet("Stylesheet:", xsl); + + // create default transformer (namespace aware) + TransformerFactory tf1 = TransformerFactory.newInstance(); + ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes()); + Transformer t1 = tf1.newTransformer(new StreamSource(bais)); + + // test transformation from stream source with namespace support + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bais = new ByteArrayInputStream(sourceXml.getBytes()); + t1.transform(new StreamSource(bais), new StreamResult(baos)); + verifyResult("StreamSource with namespace support", baos.toString(), 0, 1); + + // test transformation from DOM source with namespace support + bais.reset(); + baos.reset(); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + Document doc = dbf.newDocumentBuilder().parse(new InputSource(bais)); + t1.transform(new DOMSource(doc), new StreamResult(baos)); + verifyResult("DOMSource with namespace support", baos.toString(), 0, 1); + + // test transformation from DOM source without namespace support + bais.reset(); + baos.reset(); + dbf.setNamespaceAware(false); + doc = dbf.newDocumentBuilder().parse(new InputSource(bais)); + t1.transform(new DOMSource(doc), new StreamResult(baos)); + verifyResult("DOMSource without namespace support", baos.toString(), 3, 3); + + // test transformation from SAX source with namespace support + bais.reset(); + baos.reset(); + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + XMLReader xmlr = spf.newSAXParser().getXMLReader(); + SAXSource saxS = new SAXSource(xmlr, new InputSource(bais)); + t1.transform(saxS, new StreamResult(baos)); + verifyResult("SAXSource with namespace support", baos.toString(), 0, 1); + + // test transformation from SAX source without namespace support + bais.reset(); + baos.reset(); + spf.setNamespaceAware(false); + xmlr = spf.newSAXParser().getXMLReader(); + saxS = new SAXSource(xmlr, new InputSource(bais)); + t1.transform(saxS, new StreamResult(baos)); + verifyResult("SAXSource without namespace support", baos.toString(), 3, 3); + } + } + + /* + * @bug 8169631 + * @summary Test combinations of namespace awareness settings on + * XSL transformations + */ + @Test + public final void testBug8169631() throws IOException, SAXException, + TransformerException, ParserConfigurationException + { + new Test8169631().run(); + } + /* * @bug 8150704 - * @summary Test that XSL transformation with lots of temporary result trees will not run out of DTM IDs. + * @summary Test that XSL transformation with lots of temporary result + * trees will not run out of DTM IDs. */ @Test public final void testBug8150704() throws TransformerException, IOException { @@ -375,16 +472,8 @@ System.out.println("Passed."); } - /* - * @bug 8162598 - * @summary Test XSLTC handling of namespaces, especially empty namespace definitions to reset the - * default namespace - */ - @Test - public final void testBug8162598() throws IOException, TransformerException { - final String LINE_SEPARATOR = getSystemProperty("line.separator"); - - final String xsl = + private static class Test8162598 extends TestTemplate { + private static final String xsl = "" + LINE_SEPARATOR + "" + LINE_SEPARATOR + " " + LINE_SEPARATOR + @@ -402,39 +491,85 @@ " " + LINE_SEPARATOR + ""; - - final String sourceXml = - "" + LINE_SEPARATOR; + private static final String sourceXml = + "" + LINE_SEPARATOR; + /** + * Utility method for testBug8162598(). + * Provides a convenient way to check/assert the expected namespaces + * of a Node and its siblings. + * + * @param test + * The node to check + * @param nstest + * Expected namespace of the node + * @param nsb + * Expected namespace of the first sibling + * @param nsc + * Expected namespace of the first sibling of the first sibling + */ - System.out.println("Stylesheet:"); - System.out.println("============================="); - System.out.println(xsl); - System.out.println(); - - System.out.println("Source before transformation:"); - System.out.println("============================="); - System.out.println(sourceXml); - System.out.println(); + private void checkNodeNS(Node test, String nstest, String nsb, String nsc) { + String testNodeName = test.getNodeName(); + if (nstest == null) { + Assert.assertNull(test.getNamespaceURI(), "unexpected namespace for " + testNodeName); + } else { + Assert.assertEquals(test.getNamespaceURI(), nstest, "unexpected namespace for " + testNodeName); + } + Node b = test.getChildNodes().item(0); + if (nsb == null) { + Assert.assertNull(b.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b"); + } else { + Assert.assertEquals(b.getNamespaceURI(), nsb, "unexpected namespace for " + testNodeName + "->b"); + } + Node c = b.getChildNodes().item(0); + if (nsc == null) { + Assert.assertNull(c.getNamespaceURI(), "unexpected namespace for " + testNodeName + "->b->c"); + } else { + Assert.assertEquals(c.getNamespaceURI(), nsc, "unexpected namespace for " + testNodeName + "->b->c"); + } + } - // transform to DOM result - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer t = tf.newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes()))); - DOMResult result = new DOMResult(); - t.transform(new StreamSource(new ByteArrayInputStream(sourceXml.getBytes())), result); - Document document = (Document)result.getNode(); + public void run() throws IOException, TransformerException { + printSnippet("Source:", sourceXml); + + printSnippet("Stylesheet:", xsl); + + // transform to DOM result + TransformerFactory tf = TransformerFactory.newInstance(); + ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes()); + Transformer t = tf.newTransformer(new StreamSource(bais)); + DOMResult result = new DOMResult(); + bais = new ByteArrayInputStream(sourceXml.getBytes()); + t.transform(new StreamSource(bais), result); + Document document = (Document)result.getNode(); + + System.out.println("Result after transformation:"); + System.out.println("============================"); + OutputFormat format = new OutputFormat(); + format.setIndenting(true); + new XMLSerializer(System.out, format).serialize(document); + System.out.println(); - System.out.println("Result after transformation:"); - System.out.println("============================"); - OutputFormat format = new OutputFormat(); - format.setIndenting(true); - new XMLSerializer(System.out, format).serialize(document); - System.out.println(); - checkNodeNS8162598(document.getElementsByTagName("test1").item(0), "ns2", "ns2", null); - checkNodeNS8162598(document.getElementsByTagName("test2").item(0), "ns1", "ns2", null); - checkNodeNS8162598(document.getElementsByTagName("test3").item(0), null, null, null); - checkNodeNS8162598(document.getElementsByTagName("test4").item(0), null, null, null); - checkNodeNS8162598(document.getElementsByTagName("test5").item(0), "ns1", "ns1", null); - Assert.assertNull(document.getElementsByTagName("test6").item(0).getNamespaceURI(), "unexpected namespace for test6"); + checkNodeNS(document.getElementsByTagName("test1").item(0), "ns2", "ns2", null); + checkNodeNS(document.getElementsByTagName("test2").item(0), "ns1", "ns2", null); + checkNodeNS(document.getElementsByTagName("test3").item(0), null, null, null); + checkNodeNS(document.getElementsByTagName("test4").item(0), null, null, null); + checkNodeNS(document.getElementsByTagName("test5").item(0), "ns1", "ns1", null); + Assert.assertNull(document.getElementsByTagName("test6").item(0).getNamespaceURI(), + "unexpected namespace for test6"); + } + } + + /* + * @bug 8162598 + * @summary Test XSLTC handling of namespaces, especially empty namespace + * definitions to reset the default namespace + */ + @Test + public final void testBug8162598() throws IOException, + TransformerException + { + new Test8162598().run(); } /** diff -r 047a57b0839a -r 1c9922f121ff jaxws/.hgtags --- a/jaxws/.hgtags Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/.hgtags Wed Jul 05 22:42:01 2017 +0200 @@ -397,3 +397,4 @@ 72554d319b474b3636c7d02fe3c110254d111b1a jdk-9+149 77e4e30d9d111272cd4a45a2203e8f570d40b12e jdk-9+150 c48b4d4768b1c2b8fe5d1a844ca13732e5dfbe2a jdk-9+151 +6f8fb1cf7e5f61c40dcc3654f9a623c505f6de1f jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/DetailImpl.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * 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,13 +47,13 @@ public DetailEntry addDetailEntry(Name name) throws SOAPException { DetailEntry entry = createDetailEntry(name); addNode(entry); - return (DetailEntry) circumventBug5034339(entry); + return entry; } public DetailEntry addDetailEntry(QName qname) throws SOAPException { DetailEntry entry = createDetailEntry(qname); addNode(entry); - return (DetailEntry) circumventBug5034339(entry); + return entry; } protected SOAPElement addElement(Name name) throws SOAPException { @@ -119,28 +119,4 @@ return true; } - //overriding this method since the only two uses of this method - // are in ElementImpl and DetailImpl - //whereas the original base impl does the correct job for calls to it inside ElementImpl - // But it would not work for DetailImpl. - protected SOAPElement circumventBug5034339(SOAPElement element) { - - Name elementName = element.getElementName(); - if (!isNamespaceQualified(elementName)) { - String prefix = elementName.getPrefix(); - String defaultNamespace = getNamespaceURI(prefix); - if (defaultNamespace != null) { - Name newElementName = - NameImpl.create( - elementName.getLocalName(), - elementName.getPrefix(), - defaultNamespace); - SOAPElement newElement = createDetailEntry(newElementName); - replaceChild(newElement, element); - return newElement; - } - } - return element; - } - } diff -r 047a57b0839a -r 1c9922f121ff jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,8 +127,11 @@ } public SOAPElement addChildElement(String localName) throws SOAPException { - return (SOAPElement) addChildElement( - NameImpl.createFromUnqualifiedName(localName)); + String nsUri = getNamespaceURI(""); + Name name = (nsUri == null || nsUri.isEmpty()) + ? NameImpl.createFromUnqualifiedName(localName) + : NameImpl.createFromQualifiedName(localName, nsUri); + return addChildElement(name); } public SOAPElement addChildElement(String localName, String prefix) @@ -372,13 +375,13 @@ protected SOAPElement addElement(Name name) throws SOAPException { SOAPElement newElement = createElement(name); addNode(newElement); - return circumventBug5034339(newElement); + return newElement; } protected SOAPElement addElement(QName name) throws SOAPException { SOAPElement newElement = createElement(name); addNode(newElement); - return circumventBug5034339(newElement); + return newElement; } protected SOAPElement createElement(Name name) { @@ -1226,26 +1229,6 @@ return !"".equals(name.getNamespaceURI()); } - protected SOAPElement circumventBug5034339(SOAPElement element) { - - Name elementName = element.getElementName(); - if (!isNamespaceQualified(elementName)) { - String prefix = elementName.getPrefix(); - String defaultNamespace = getNamespaceURI(prefix); - if (defaultNamespace != null) { - Name newElementName = - NameImpl.create( - elementName.getLocalName(), - elementName.getPrefix(), - defaultNamespace); - SOAPElement newElement = createElement(newElementName); - replaceChild(newElement, element); - return newElement; - } - } - return element; - } - //TODO: This is a temporary SAAJ workaround for optimizing XWS // should be removed once the corresponding JAXP bug is fixed // It appears the bug will be fixed in JAXP 1.4 (not by Appserver 9 timeframe) diff -r 047a57b0839a -r 1c9922f121ff jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/util/stax/SaajStaxWriter.java --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/util/stax/SaajStaxWriter.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/messaging/saaj/util/stax/SaajStaxWriter.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,8 +25,10 @@ package com.sun.xml.internal.messaging.saaj.util.stax; +import java.util.Iterator; import java.util.Arrays; -import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; @@ -42,6 +44,17 @@ /** * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface. * + *

+ * Defers creation of SOAPElement until all the aspects of the name of the element are known. + * In some cases, the namespace uri is indicated only by the {@link #writeNamespace(String, String)} call. + * After opening an element ({@code writeStartElement}, {@code writeEmptyElement} methods), all attributes + * and namespace assignments are retained within {@link DeferredElement} object ({@code deferredElement} field). + * As soon as any other method than {@code writeAttribute}, {@code writeNamespace}, {@code writeDefaultNamespace} + * or {@code setNamespace} is called, the contents of {@code deferredElement} is transformed into new SOAPElement + * (which is appropriately inserted into the SOAPMessage under construction). + * This mechanism is necessary to fix JDK-8159058 issue. + *

+ * * @author shih-chang.chen@oracle.com */ public class SaajStaxWriter implements XMLStreamWriter { @@ -49,6 +62,7 @@ protected SOAPMessage soap; protected String envURI; protected SOAPElement currentElement; + protected DeferredElement deferredElement; static final protected String Envelope = "Envelope"; static final protected String Header = "Header"; @@ -58,6 +72,7 @@ public SaajStaxWriter(final SOAPMessage msg, String uri) throws SOAPException { soap = msg; this.envURI = uri; + this.deferredElement = new DeferredElement(); } public SOAPMessage getSOAPMessage() { @@ -70,11 +85,8 @@ @Override public void writeStartElement(final String localName) throws XMLStreamException { - try { - currentElement = currentElement.addChildElement(localName); - } catch (SOAPException e) { - throw new XMLStreamException(e); - } + currentElement = deferredElement.flushTo(currentElement); + deferredElement.setLocalName(localName); } @Override @@ -84,8 +96,10 @@ @Override public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException { - try { - if (envURI.equals(ns)) { + currentElement = deferredElement.flushTo(currentElement); + + if (envURI.equals(ns)) { + try { if (Envelope.equals(ln)) { currentElement = getEnvelope(); fixPrefix(prefix); @@ -99,13 +113,16 @@ fixPrefix(prefix); return; } + } catch (SOAPException e) { + throw new XMLStreamException(e); } - currentElement = (prefix == null) ? - currentElement.addChildElement(new QName(ns, ln)) : - currentElement.addChildElement(ln, prefix, ns); - } catch (SOAPException e) { - throw new XMLStreamException(e); + } + + deferredElement.setLocalName(ln); + deferredElement.setNamespaceUri(ns); + deferredElement.setPrefix(prefix); + } private void fixPrefix(final String prfx) throws XMLStreamException { @@ -136,11 +153,13 @@ @Override public void writeEndElement() throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); if (currentElement != null) currentElement = currentElement.getParentElement(); } @Override public void writeEndDocument() throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); } @Override @@ -158,19 +177,14 @@ @Override public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException { - try { - if (ns == null) { - if (prefix == null && xmlns.equals(ln)) { - currentElement.addNamespaceDeclaration("", value); - } else { - currentElement.setAttributeNS("", ln, value); - } + if (ns == null && prefix == null && xmlns.equals(ln)) { + writeNamespace("", value); + } else { + if (deferredElement.isInitialized()) { + deferredElement.addAttribute(prefix, ns, ln, value); } else { - QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix); - currentElement.addAttribute(name, value); + addAttibuteToElement(currentElement, prefix, ns, ln, value); } - } catch (SOAPException e) { - throw new XMLStreamException(e); } } @@ -181,16 +195,16 @@ @Override public void writeNamespace(String prefix, final String uri) throws XMLStreamException { - // make prefix default if null or "xmlns" (according to javadoc) - if (prefix == null || "xmlns".equals(prefix)) { - prefix = ""; - } - - try { - currentElement.addNamespaceDeclaration(prefix, uri); - } catch (SOAPException e) { - throw new XMLStreamException(e); + String thePrefix = prefix == null || "xmlns".equals(prefix) ? "" : prefix; + if (deferredElement.isInitialized()) { + deferredElement.addNamespaceDeclaration(thePrefix, uri); + } else { + try { + currentElement.addNamespaceDeclaration(thePrefix, uri); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } } } @@ -201,35 +215,40 @@ @Override public void writeComment(final String data) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Comment c = soap.getSOAPPart().createComment(data); currentElement.appendChild(c); } @Override public void writeProcessingInstruction(final String target) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createProcessingInstruction(target, ""); currentElement.appendChild(n); } @Override public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createProcessingInstruction(target, data); currentElement.appendChild(n); } @Override public void writeCData(final String data) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createCDATASection(data); currentElement.appendChild(n); } @Override public void writeDTD(final String dtd) throws XMLStreamException { - //TODO ... Don't do anything here + currentElement = deferredElement.flushTo(currentElement); } @Override public void writeEntityRef(final String name) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createEntityReference(name); currentElement.appendChild(n); } @@ -257,6 +276,7 @@ @Override public void writeCharacters(final String text) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); try { currentElement.addTextNode(text); } catch (SOAPException e) { @@ -266,6 +286,7 @@ @Override public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len); try { currentElement.addTextNode(new String(chr)); @@ -281,10 +302,16 @@ @Override public void setPrefix(final String prefix, final String uri) throws XMLStreamException { - try { - this.currentElement.addNamespaceDeclaration(prefix, uri); - } catch (SOAPException e) { - throw new XMLStreamException(e); + // TODO: this in fact is not what would be expected from XMLStreamWriter + // (e.g. XMLStreamWriter for writing to output stream does not write anything as result of + // this method, it just rememebers that given prefix is associated with the given uri + // for the scope; to actually declare the prefix assignment in the resulting XML, one + // needs to call writeNamespace(...) method + // Kept for backwards compatibility reasons - this might be worth of further investigation. + if (deferredElement.isInitialized()) { + deferredElement.addNamespaceDeclaration(prefix, uri); + } else { + throw new XMLStreamException("Namespace not associated with any element"); } } @@ -331,4 +358,209 @@ } }; } + + static void addAttibuteToElement(SOAPElement element, String prefix, String ns, String ln, String value) + throws XMLStreamException { + try { + if (ns == null) { + element.setAttributeNS("", ln, value); + } else { + QName name = prefix == null ? new QName(ns, ln) : new QName(ns, ln, prefix); + element.addAttribute(name, value); + } + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + /** + * Holds details of element that needs to be deferred in order to manage namespace assignments correctly. + * + *

+ * An instance of can be set with all the aspects of the element name (local name, prefix, namespace uri). + * Attributes and namespace declarations (special case of attribute) can be added. + * Namespace declarations are handled so that the element namespace is updated if it is implied by the namespace + * declaration and the namespace was not set to non-{@code null} value previously. + *

+ * + *

+ * The state of this object can be {@link #flushTo(SOAPElement) flushed} to SOAPElement - new SOAPElement will + * be added a child element; the new element will have exactly the shape as represented by the state of this + * object. Note that the {@link #flushTo(SOAPElement)} method does nothing + * (and returns the argument immediately) if the state of this object is not initialized + * (i.e. local name is null). + *

+ * + * @author ondrej.cerny@oracle.com + */ + static class DeferredElement { + private String prefix; + private String localName; + private String namespaceUri; + private final List namespaceDeclarations; + private final List attributeDeclarations; + + DeferredElement() { + this.namespaceDeclarations = new LinkedList(); + this.attributeDeclarations = new LinkedList(); + reset(); + } + + + /** + * Set prefix of the element. + * @param prefix namespace prefix + */ + public void setPrefix(final String prefix) { + this.prefix = prefix; + } + + /** + * Set local name of the element. + * + *

+ * This method initializes the element. + *

+ * + * @param localName local name {@code not null} + */ + public void setLocalName(final String localName) { + if (localName == null) { + throw new IllegalArgumentException("localName can not be null"); + } + this.localName = localName; + } + + /** + * Set namespace uri. + * + * @param namespaceUri namespace uri + */ + public void setNamespaceUri(final String namespaceUri) { + this.namespaceUri = namespaceUri; + } + + /** + * Adds namespace prefix assignment to the element. + * + * @param prefix prefix (not {@code null}) + * @param namespaceUri namespace uri + */ + public void addNamespaceDeclaration(final String prefix, final String namespaceUri) { + if (null == this.namespaceUri && null != namespaceUri && prefix.equals(emptyIfNull(this.prefix))) { + this.namespaceUri = namespaceUri; + } + this.namespaceDeclarations.add(new NamespaceDeclaration(prefix, namespaceUri)); + } + + /** + * Adds attribute to the element. + * @param prefix prefix + * @param ns namespace + * @param ln local name + * @param value value + */ + public void addAttribute(final String prefix, final String ns, final String ln, final String value) { + if (ns == null && prefix == null && xmlns.equals(ln)) { + this.addNamespaceDeclaration(prefix, value); + } else { + this.attributeDeclarations.add(new AttributeDeclaration(prefix, ns, ln, value)); + } + } + + /** + * Flushes state of this element to the {@code target} element. + * + *

+ * If this element is initialized then it is added with all the namespace declarations and attributes + * to the {@code target} element as a child. The state of this element is reset to uninitialized. + * The newly added element object is returned. + *

+ *

+ * If this element is not initialized then the {@code target} is returned immediately, nothing else is done. + *

+ * + * @param target target element + * @return {@code target} or new element + * @throws XMLStreamException on error + */ + public SOAPElement flushTo(final SOAPElement target) throws XMLStreamException { + try { + if (this.localName != null) { + // add the element appropriately (based on namespace declaration) + final SOAPElement newElement; + if (this.namespaceUri == null) { + // add element with inherited scope + newElement = target.addChildElement(this.localName); + } else if (prefix == null) { + newElement = target.addChildElement(new QName(this.namespaceUri, this.localName)); + } else { + newElement = target.addChildElement(this.localName, this.prefix, this.namespaceUri); + } + // add namespace declarations + for (NamespaceDeclaration namespace : this.namespaceDeclarations) { + target.addNamespaceDeclaration(namespace.prefix, namespace.namespaceUri); + } + // add attribute declarations + for (AttributeDeclaration attribute : this.attributeDeclarations) { + addAttibuteToElement(newElement, + attribute.prefix, attribute.namespaceUri, attribute.localName, attribute.value); + } + // reset state + this.reset(); + + return newElement; + } else { + return target; + } + // else after reset state -> not initialized + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + /** + * Is the element initialized? + * @return boolean indicating whether it was initialized after last flush + */ + public boolean isInitialized() { + return this.localName != null; + } + + private void reset() { + this.localName = null; + this.prefix = null; + this.namespaceUri = null; + this.namespaceDeclarations.clear(); + this.attributeDeclarations.clear(); + } + + private static String emptyIfNull(String s) { + return s == null ? "" : s; + } + } + + static class NamespaceDeclaration { + final String prefix; + final String namespaceUri; + + NamespaceDeclaration(String prefix, String namespaceUri) { + this.prefix = prefix; + this.namespaceUri = namespaceUri; + } + } + + static class AttributeDeclaration { + final String prefix; + final String namespaceUri; + final String localName; + final String value; + + AttributeDeclaration(String prefix, String namespaceUri, String localName, String value) { + this.prefix = prefix; + this.namespaceUri = namespaceUri; + this.localName = localName; + this.value = value; + } + } } diff -r 047a57b0839a -r 1c9922f121ff jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * 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,8 +25,10 @@ package com.sun.xml.internal.ws.api.message.saaj; +import java.util.Iterator; import java.util.Arrays; -import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; @@ -42,6 +44,17 @@ /** * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface. * + *

+ * Defers creation of SOAPElement until all the aspects of the name of the element are known. + * In some cases, the namespace uri is indicated only by the {@link #writeNamespace(String, String)} call. + * After opening an element ({@code writeStartElement}, {@code writeEmptyElement} methods), all attributes + * and namespace assignments are retained within {@link DeferredElement} object ({@code deferredElement} field). + * As soon as any other method than {@code writeAttribute}, {@code writeNamespace}, {@code writeDefaultNamespace} + * or {@code setNamespace} is called, the contents of {@code deferredElement} is transformed into new SOAPElement + * (which is appropriately inserted into the SOAPMessage under construction). + * This mechanism is necessary to fix JDK-8159058 issue. + *

+ * * @author shih-chang.chen@oracle.com */ public class SaajStaxWriter implements XMLStreamWriter { @@ -49,6 +62,7 @@ protected SOAPMessage soap; protected String envURI; protected SOAPElement currentElement; + protected DeferredElement deferredElement; static final protected String Envelope = "Envelope"; static final protected String Header = "Header"; @@ -58,6 +72,7 @@ public SaajStaxWriter(final SOAPMessage msg, String uri) throws SOAPException { soap = msg; this.envURI = uri; + this.deferredElement = new DeferredElement(); } public SOAPMessage getSOAPMessage() { @@ -70,11 +85,8 @@ @Override public void writeStartElement(final String localName) throws XMLStreamException { - try { - currentElement = currentElement.addChildElement(localName); - } catch (SOAPException e) { - throw new XMLStreamException(e); - } + currentElement = deferredElement.flushTo(currentElement); + deferredElement.setLocalName(localName); } @Override @@ -84,8 +96,10 @@ @Override public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException { - try { - if (envURI.equals(ns)) { + currentElement = deferredElement.flushTo(currentElement); + + if (envURI.equals(ns)) { + try { if (Envelope.equals(ln)) { currentElement = getEnvelope(); fixPrefix(prefix); @@ -99,13 +113,16 @@ fixPrefix(prefix); return; } + } catch (SOAPException e) { + throw new XMLStreamException(e); } - currentElement = (prefix == null) ? - currentElement.addChildElement(new QName(ns, ln)) : - currentElement.addChildElement(ln, prefix, ns); - } catch (SOAPException e) { - throw new XMLStreamException(e); + } + + deferredElement.setLocalName(ln); + deferredElement.setNamespaceUri(ns); + deferredElement.setPrefix(prefix); + } private void fixPrefix(final String prfx) throws XMLStreamException { @@ -136,11 +153,13 @@ @Override public void writeEndElement() throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); if (currentElement != null) currentElement = currentElement.getParentElement(); } @Override public void writeEndDocument() throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); } @Override @@ -158,19 +177,14 @@ @Override public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException { - try { - if (ns == null) { - if (prefix == null && xmlns.equals(ln)) { - currentElement.addNamespaceDeclaration("", value); - } else { - currentElement.setAttributeNS("", ln, value); - } + if (ns == null && prefix == null && xmlns.equals(ln)) { + writeNamespace("", value); + } else { + if (deferredElement.isInitialized()) { + deferredElement.addAttribute(prefix, ns, ln, value); } else { - QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix); - currentElement.addAttribute(name, value); + addAttibuteToElement(currentElement, prefix, ns, ln, value); } - } catch (SOAPException e) { - throw new XMLStreamException(e); } } @@ -181,16 +195,16 @@ @Override public void writeNamespace(String prefix, final String uri) throws XMLStreamException { - // make prefix default if null or "xmlns" (according to javadoc) - if (prefix == null || "xmlns".equals(prefix)) { - prefix = ""; - } - - try { - currentElement.addNamespaceDeclaration(prefix, uri); - } catch (SOAPException e) { - throw new XMLStreamException(e); + String thePrefix = prefix == null || "xmlns".equals(prefix) ? "" : prefix; + if (deferredElement.isInitialized()) { + deferredElement.addNamespaceDeclaration(thePrefix, uri); + } else { + try { + currentElement.addNamespaceDeclaration(thePrefix, uri); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } } } @@ -201,35 +215,40 @@ @Override public void writeComment(final String data) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Comment c = soap.getSOAPPart().createComment(data); currentElement.appendChild(c); } @Override public void writeProcessingInstruction(final String target) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createProcessingInstruction(target, ""); currentElement.appendChild(n); } @Override public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createProcessingInstruction(target, data); currentElement.appendChild(n); } @Override public void writeCData(final String data) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createCDATASection(data); currentElement.appendChild(n); } @Override public void writeDTD(final String dtd) throws XMLStreamException { - //TODO ... Don't do anything here + currentElement = deferredElement.flushTo(currentElement); } @Override public void writeEntityRef(final String name) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); Node n = soap.getSOAPPart().createEntityReference(name); currentElement.appendChild(n); } @@ -257,6 +276,7 @@ @Override public void writeCharacters(final String text) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); try { currentElement.addTextNode(text); } catch (SOAPException e) { @@ -266,6 +286,7 @@ @Override public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException { + currentElement = deferredElement.flushTo(currentElement); char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len); try { currentElement.addTextNode(new String(chr)); @@ -281,10 +302,16 @@ @Override public void setPrefix(final String prefix, final String uri) throws XMLStreamException { - try { - this.currentElement.addNamespaceDeclaration(prefix, uri); - } catch (SOAPException e) { - throw new XMLStreamException(e); + // TODO: this in fact is not what would be expected from XMLStreamWriter + // (e.g. XMLStreamWriter for writing to output stream does not write anything as result of + // this method, it just rememebers that given prefix is associated with the given uri + // for the scope; to actually declare the prefix assignment in the resulting XML, one + // needs to call writeNamespace(...) method + // Kept for backwards compatibility reasons - this might be worth of further investigation. + if (deferredElement.isInitialized()) { + deferredElement.addNamespaceDeclaration(prefix, uri); + } else { + throw new XMLStreamException("Namespace not associated with any element"); } } @@ -315,12 +342,12 @@ return currentElement.lookupPrefix(namespaceURI); } public Iterator getPrefixes(final String namespaceURI) { - return new Iterator() { + return new Iterator() { String prefix = getPrefix(namespaceURI); public boolean hasNext() { return (prefix != null); } - public Object next() { + public String next() { if (!hasNext()) throw new java.util.NoSuchElementException(); String next = prefix; prefix = null; @@ -331,4 +358,209 @@ } }; } + + static void addAttibuteToElement(SOAPElement element, String prefix, String ns, String ln, String value) + throws XMLStreamException { + try { + if (ns == null) { + element.setAttributeNS("", ln, value); + } else { + QName name = prefix == null ? new QName(ns, ln) : new QName(ns, ln, prefix); + element.addAttribute(name, value); + } + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + /** + * Holds details of element that needs to be deferred in order to manage namespace assignments correctly. + * + *

+ * An instance of can be set with all the aspects of the element name (local name, prefix, namespace uri). + * Attributes and namespace declarations (special case of attribute) can be added. + * Namespace declarations are handled so that the element namespace is updated if it is implied by the namespace + * declaration and the namespace was not set to non-{@code null} value previously. + *

+ * + *

+ * The state of this object can be {@link #flushTo(SOAPElement) flushed} to SOAPElement - new SOAPElement will + * be added a child element; the new element will have exactly the shape as represented by the state of this + * object. Note that the {@link #flushTo(SOAPElement)} method does nothing + * (and returns the argument immediately) if the state of this object is not initialized + * (i.e. local name is null). + *

+ * + * @author ondrej.cerny@oracle.com + */ + static class DeferredElement { + private String prefix; + private String localName; + private String namespaceUri; + private final List namespaceDeclarations; + private final List attributeDeclarations; + + DeferredElement() { + this.namespaceDeclarations = new LinkedList(); + this.attributeDeclarations = new LinkedList(); + reset(); + } + + + /** + * Set prefix of the element. + * @param prefix namespace prefix + */ + public void setPrefix(final String prefix) { + this.prefix = prefix; + } + + /** + * Set local name of the element. + * + *

+ * This method initializes the element. + *

+ * + * @param localName local name {@code not null} + */ + public void setLocalName(final String localName) { + if (localName == null) { + throw new IllegalArgumentException("localName can not be null"); + } + this.localName = localName; + } + + /** + * Set namespace uri. + * + * @param namespaceUri namespace uri + */ + public void setNamespaceUri(final String namespaceUri) { + this.namespaceUri = namespaceUri; + } + + /** + * Adds namespace prefix assignment to the element. + * + * @param prefix prefix (not {@code null}) + * @param namespaceUri namespace uri + */ + public void addNamespaceDeclaration(final String prefix, final String namespaceUri) { + if (null == this.namespaceUri && null != namespaceUri && prefix.equals(emptyIfNull(this.prefix))) { + this.namespaceUri = namespaceUri; + } + this.namespaceDeclarations.add(new NamespaceDeclaration(prefix, namespaceUri)); + } + + /** + * Adds attribute to the element. + * @param prefix prefix + * @param ns namespace + * @param ln local name + * @param value value + */ + public void addAttribute(final String prefix, final String ns, final String ln, final String value) { + if (ns == null && prefix == null && xmlns.equals(ln)) { + this.addNamespaceDeclaration(prefix, value); + } else { + this.attributeDeclarations.add(new AttributeDeclaration(prefix, ns, ln, value)); + } + } + + /** + * Flushes state of this element to the {@code target} element. + * + *

+ * If this element is initialized then it is added with all the namespace declarations and attributes + * to the {@code target} element as a child. The state of this element is reset to uninitialized. + * The newly added element object is returned. + *

+ *

+ * If this element is not initialized then the {@code target} is returned immediately, nothing else is done. + *

+ * + * @param target target element + * @return {@code target} or new element + * @throws XMLStreamException on error + */ + public SOAPElement flushTo(final SOAPElement target) throws XMLStreamException { + try { + if (this.localName != null) { + // add the element appropriately (based on namespace declaration) + final SOAPElement newElement; + if (this.namespaceUri == null) { + // add element with inherited scope + newElement = target.addChildElement(this.localName); + } else if (prefix == null) { + newElement = target.addChildElement(new QName(this.namespaceUri, this.localName)); + } else { + newElement = target.addChildElement(this.localName, this.prefix, this.namespaceUri); + } + // add namespace declarations + for (NamespaceDeclaration namespace : this.namespaceDeclarations) { + target.addNamespaceDeclaration(namespace.prefix, namespace.namespaceUri); + } + // add attribute declarations + for (AttributeDeclaration attribute : this.attributeDeclarations) { + addAttibuteToElement(newElement, + attribute.prefix, attribute.namespaceUri, attribute.localName, attribute.value); + } + // reset state + this.reset(); + + return newElement; + } else { + return target; + } + // else after reset state -> not initialized + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + /** + * Is the element initialized? + * @return boolean indicating whether it was initialized after last flush + */ + public boolean isInitialized() { + return this.localName != null; + } + + private void reset() { + this.localName = null; + this.prefix = null; + this.namespaceUri = null; + this.namespaceDeclarations.clear(); + this.attributeDeclarations.clear(); + } + + private static String emptyIfNull(String s) { + return s == null ? "" : s; + } + } + + static class NamespaceDeclaration { + final String prefix; + final String namespaceUri; + + NamespaceDeclaration(String prefix, String namespaceUri) { + this.prefix = prefix; + this.namespaceUri = namespaceUri; + } + } + + static class AttributeDeclaration { + final String prefix; + final String namespaceUri; + final String localName; + final String value; + + AttributeDeclaration(String prefix, String namespaceUri, String localName, String value) { + this.prefix = prefix; + this.namespaceUri = namespaceUri; + this.localName = localName; + this.value = value; + } + } } diff -r 047a57b0839a -r 1c9922f121ff jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/xml/XmlUtil.java --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/xml/XmlUtil.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/xml/XmlUtil.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.Method; +import java.net.URI; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; @@ -332,13 +333,13 @@ * (com.sun.org.apache.xml.internal) for modular runtime. */ private static EntityResolver createCatalogResolver(ArrayList urls) throws Exception { - // Prepare array of catalog paths - String[] paths = urls.stream() - .map(u -> u.toExternalForm()) - .toArray(c -> new String[c]); + // Prepare array of catalog URIs + URI[] uris = urls.stream() + .map(u -> URI.create(u.toExternalForm())) + .toArray(URI[]::new); //Create CatalogResolver with new JDK9+ API - return (EntityResolver) CatalogManager.catalogResolver(catalogFeatures, paths); + return (EntityResolver) CatalogManager.catalogResolver(catalogFeatures, uris); } // Cache CatalogFeatures instance for future usages. diff -r 047a57b0839a -r 1c9922f121ff jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/Options.java --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/Options.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/Options.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -777,13 +777,13 @@ * Adds a new catalog file. */ public void addCatalog(File catalogFile) throws IOException { - String newUrl = catalogFile.getPath(); + URI newUrl = catalogFile.toURI(); if (!catalogUrls.contains(newUrl)) { catalogUrls.add(newUrl); } try { entityResolver = CatalogManager.catalogResolver(catalogFeatures, - catalogUrls.toArray(new String[0])); + catalogUrls.stream().toArray(URI[]::new)); } catch (Exception ex) { entityResolver = null; } @@ -791,7 +791,7 @@ // Since javax.xml.catalog is unmodifiable we need to track catalog // URLs added and create new catalog each time addCatalog is called - private final ArrayList catalogUrls = new ArrayList(); + private final ArrayList catalogUrls = new ArrayList<>(); // Cache CatalogFeatures instance for future usages. // Resolve feature is set to "continue" value for backward compatibility. diff -r 047a57b0839a -r 1c9922f121ff jdk/.hgtags --- a/jdk/.hgtags Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/.hgtags Wed Jul 05 22:42:01 2017 +0200 @@ -394,3 +394,4 @@ 5a846396a24c7aff01d6a8feaa7afc0a6369f04d jdk-9+149 71e198ef3839045e829a879af1d709be16ab0f88 jdk-9+150 d27bab22ff62823902d93d1d35ca397cfd50d059 jdk-9+151 +a20f2cf90762673e1bc4980fd6597e70a2578045 jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff jdk/make/data/fontconfig/solaris.fontconfig.properties --- a/jdk/make/data/fontconfig/solaris.fontconfig.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/make/data/fontconfig/solaris.fontconfig.properties Wed Jul 05 22:42:01 2017 +0200 @@ -436,15 +436,15 @@ filename.-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arial.ttf filename.-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/ariali.ttf -filename.-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialb.ttf +filename.-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbd.ttf filename.-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbi.ttf filename.-monotype-courier_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cour.ttf filename.-monotype-courier_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/couri.ttf -filename.-monotype-courier_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courb.ttf +filename.-monotype-courier_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbd.ttf filename.-monotype-courier_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbi.ttf filename.-monotype-times_new_roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/times.ttf filename.-monotype-times_new_roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesi.ttf -filename.-monotype-times_new_roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesb.ttf +filename.-monotype-times_new_roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbd.ttf filename.-monotype-times_new_roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbi.ttf filename.-monotype-angsana_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsa.ttf diff -r 047a57b0839a -r 1c9922f121ff jdk/make/lib/Awt2dLibraries.gmk --- a/jdk/make/lib/Awt2dLibraries.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -222,6 +222,8 @@ # applies to debug builds. ifeq ($(TOOLCHAIN_TYPE), gcc) BUILD_LIBAWT_debug_mem.c_CFLAGS := -w + # This option improves performance of MaskFill in Java2D by 20% for some gcc + LIBAWT_CFLAGS += -fgcse-after-reload endif $(eval $(call SetupNativeCompilation,BUILD_LIBAWT, \ diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/io/File.java --- a/jdk/src/java.base/share/classes/java/io/File.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/io/File.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1962,6 +1962,9 @@ name = sb.toString(); } + // Normalize the path component + name = fs.normalize(name); + File f = new File(dir, name); if (!name.equals(f.getName()) || f.isInvalid()) { if (System.getSecurityManager() != null) diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/lang/Class.java --- a/jdk/src/java.base/share/classes/java/lang/Class.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/Class.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2477,7 +2477,7 @@ *
    * *
  • If the {@code name} begins with a {@code '/'} - * ('\u002f'), then the absolute name of the resource is the + * ('\u002f'), then the absolute name of the resource is the * portion of the {@code name} following the {@code '/'}. * *
  • Otherwise, the absolute name is of the following form: @@ -2488,7 +2488,7 @@ * *

    Where the {@code modified_package_name} is the package name of this * object with {@code '/'} substituted for {@code '.'} - * ('\u002e'). + * ('\u002e'). * *

* @@ -2570,7 +2570,7 @@ *
    * *
  • If the {@code name} begins with a {@code '/'} - * ('\u002f'), then the absolute name of the resource is the + * ('\u002f'), then the absolute name of the resource is the * portion of the {@code name} following the {@code '/'}. * *
  • Otherwise, the absolute name is of the following form: @@ -2581,7 +2581,7 @@ * *

    Where the {@code modified_package_name} is the package name of this * object with {@code '/'} substituted for {@code '.'} - * ('\u002e'). + * ('\u002e'). * *

* diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/lang/ClassLoader.java --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,34 +70,34 @@ /** * A class loader is an object that is responsible for loading classes. The - * class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to * locate or generate data that constitutes a definition for the class. A * typical strategy is to transform the name into a file name and then read a * "class file" of that name from a file system. * - *

Every {@link Class Class} object contains a {@link - * Class#getClassLoader() reference} to the ClassLoader that defined + *

Every {@link java.lang.Class Class} object contains a {@link + * Class#getClassLoader() reference} to the {@code ClassLoader} that defined * it. * - *

Class objects for array classes are not created by class + *

{@code Class} objects for array classes are not created by class * loaders, but are created automatically as required by the Java runtime. * The class loader for an array class, as returned by {@link * Class#getClassLoader()} is the same as the class loader for its element * type; if the element type is a primitive type, then the array class has no * class loader. * - *

Applications implement subclasses of ClassLoader in order to + *

Applications implement subclasses of {@code ClassLoader} in order to * extend the manner in which the Java virtual machine dynamically loads * classes. * *

Class loaders may typically be used by security managers to indicate * security domains. * - *

The ClassLoader class uses a delegation model to search for - * classes and resources. Each instance of ClassLoader has an + *

The {@code ClassLoader} class uses a delegation model to search for + * classes and resources. Each instance of {@code ClassLoader} has an * associated parent class loader. When requested to find a class or - * resource, a ClassLoader instance will delegate the search for the + * resource, a {@code ClassLoader} instance will delegate the search for the * class or resource to its parent class loader before attempting to find the * class or resource itself. * @@ -105,15 +105,15 @@ * {@linkplain #isRegisteredAsParallelCapable() 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 + * #registerAsParallelCapable ClassLoader.registerAsParallelCapable} + * method. Note that the {@code ClassLoader} class is registered as parallel * capable by default. However, its subclasses still need to register themselves * if they are parallel capable. * In environments in which the delegation model is not strictly * hierarchical, class loaders need to be parallel capable, otherwise class * loading can lead to deadlocks because the loader lock is held for the * duration of the class loading process (see {@link #loadClass - * loadClass} methods). + * loadClass} methods). * *

Run-time Built-in Class Loaders

* @@ -143,13 +143,13 @@ * However, some classes may not originate from a file; they may originate * from other sources, such as the network, or they could be constructed by an * application. The method {@link #defineClass(String, byte[], int, int) - * defineClass} converts an array of bytes into an instance of class - * Class. Instances of this newly defined class can be created using - * {@link Class#newInstance Class.newInstance}. + * defineClass} converts an array of bytes into an instance of class + * {@code Class}. Instances of this newly defined class can be created using + * {@link Class#newInstance Class.newInstance}. * *

The methods and constructors of objects created by a class loader may * reference other classes. To determine the class(es) referred to, the Java - * virtual machine invokes the {@link #loadClass loadClass} method of + * virtual machine invokes the {@link #loadClass loadClass} method of * the class loader that originally created the class. * *

For example, an application could create a network class loader to @@ -162,9 +162,9 @@ *

* *

The network class loader subclass must define the methods {@link - * #findClass findClass} and loadClassData to load a class + * #findClass findClass} and {@code loadClassData} to load a class * from the network. Once it has downloaded the bytes that make up the class, - * it should use the method {@link #defineClass defineClass} to + * it should use the method {@link #defineClass defineClass} to * create a class instance. A sample implementation is: * *

@@ -392,7 +392,7 @@
      *
      * 

If there is a security manager, its {@link * SecurityManager#checkCreateClassLoader() - * checkCreateClassLoader} method is invoked. This may result in + * checkCreateClassLoader} method is invoked. This may result in * a security exception.

* * @param parent @@ -400,7 +400,7 @@ * * @throws SecurityException * If a security manager exists and its - * checkCreateClassLoader method doesn't allow creation + * {@code checkCreateClassLoader} method doesn't allow creation * of a new class loader. * * @since 1.2 @@ -410,18 +410,18 @@ } /** - * Creates a new class loader using the ClassLoader returned by + * Creates a new class loader using the {@code ClassLoader} returned by * the method {@link #getSystemClassLoader() - * getSystemClassLoader()} as the parent class loader. + * getSystemClassLoader()} as the parent class loader. * *

If there is a security manager, its {@link * SecurityManager#checkCreateClassLoader() - * checkCreateClassLoader} method is invoked. This may result in + * checkCreateClassLoader} method is invoked. This may result in * a security exception.

* * @throws SecurityException * If a security manager exists and its - * checkCreateClassLoader method doesn't allow creation + * {@code checkCreateClassLoader} method doesn't allow creation * of a new class loader. */ protected ClassLoader() { @@ -458,13 +458,13 @@ * This method searches for classes in the same manner as the {@link * #loadClass(String, boolean)} method. It is invoked by the Java virtual * machine to resolve class references. Invoking this method is equivalent - * to invoking {@link #loadClass(String, boolean) loadClass(name, - * false)}. + * to invoking {@link #loadClass(String, boolean) loadClass(name, + * false)}. * * @param name * The binary name of the class * - * @return The resulting Class object + * @return The resulting {@code Class} object * * @throws ClassNotFoundException * If the class was not found @@ -483,8 +483,8 @@ *
  • Invoke {@link #findLoadedClass(String)} to check if the class * has already been loaded.

  • * - *
  • Invoke the {@link #loadClass(String) loadClass} method - * on the parent class loader. If the parent is null the class + *

  • Invoke the {@link #loadClass(String) loadClass} method + * on the parent class loader. If the parent is {@code null} the class * loader built-in to the virtual machine is used, instead.

  • * *
  • Invoke the {@link #findClass(String)} method to find the @@ -493,23 +493,23 @@ * * *

    If the class was found using the above steps, and the - * resolve flag is true, this method will then invoke the {@link - * #resolveClass(Class)} method on the resulting Class object. + * {@code resolve} flag is true, this method will then invoke the {@link + * #resolveClass(Class)} method on the resulting {@code Class} object. * - *

    Subclasses of ClassLoader are encouraged to override {@link + *

    Subclasses of {@code ClassLoader} are encouraged to override {@link * #findClass(String)}, rather than this method.

    * *

    Unless overridden, this method synchronizes on the result of - * {@link #getClassLoadingLock getClassLoadingLock} method + * {@link #getClassLoadingLock getClassLoadingLock} method * during the entire class loading process. * * @param name * The binary name of the class * * @param resolve - * If true then resolve the class + * If {@code true} then resolve the class * - * @return The resulting Class object + * @return The resulting {@code Class} object * * @throws ClassNotFoundException * If the class could not be found @@ -606,7 +606,7 @@ * @return the lock for class loading operations * * @throws NullPointerException - * If registered as parallel capable and className is null + * If registered as parallel capable and {@code className} is null * * @see #loadClass(String, boolean) * @@ -667,14 +667,14 @@ * Finds the class with the specified binary name. * This method should be overridden by class loader implementations that * follow the delegation model for loading classes, and will be invoked by - * the {@link #loadClass loadClass} method after checking the + * the {@link #loadClass loadClass} method after checking the * parent class loader for the requested class. The default implementation - * throws a ClassNotFoundException. + * throws a {@code ClassNotFoundException}. * * @param name * The binary name of the class * - * @return The resulting Class object + * @return The resulting {@code Class} object * * @throws ClassNotFoundException * If the class could not be found @@ -722,32 +722,32 @@ /** - * Converts an array of bytes into an instance of class Class. - * Before the Class can be used it must be resolved. This method + * Converts an array of bytes into an instance of class {@code Class}. + * Before the {@code Class} can be used it must be resolved. This method * is deprecated in favor of the version that takes a binary name as its first argument, and is more secure. * * @param b * The bytes that make up the class data. The bytes in positions - * off through off+len-1 should have the format + * {@code off} through {@code off+len-1} should have the format * of a valid class file as defined by * The Java™ Virtual Machine Specification. * * @param off - * The start offset in b of the class data + * The start offset in {@code b} of the class data * * @param len * The length of the class data * - * @return The Class object that was created from the specified + * @return The {@code Class} object that was created from the specified * class data * * @throws ClassFormatError * If the data did not contain a valid class * * @throws IndexOutOfBoundsException - * If either off or len is negative, or if - * off+len is greater than b.length. + * If either {@code off} or {@code len} is negative, or if + * {@code off+len} is greater than {@code b.length}. * * @throws SecurityException * If an attempt is made to add this class to a package that @@ -994,11 +994,11 @@ * #defineClass(String, byte[], int, int, ProtectionDomain)}. * *

    An invocation of this method of the form - * cl.defineClass(name, - * bBuffer, pd) yields exactly the same + * cl{@code .defineClass(}name{@code ,} + * bBuffer{@code ,} pd{@code )} yields exactly the same * result as the statements * - *

    + *

    * ...
    * byte[] temp = new byte[bBuffer.{@link * java.nio.ByteBuffer#remaining remaining}()];
    @@ -1007,16 +1007,16 @@ * return {@link #defineClass(String, byte[], int, int, ProtectionDomain) * cl.defineClass}(name, temp, 0, * temp.length, pd);
    - *

    + *

    * * @param name * The expected binary name. of the class, or - * null if not known + * {@code null} if not known * * @param b * The bytes that make up the class data. The bytes from positions - * b.position() through b.position() + b.limit() -1 - * should have the format of a valid class file as defined by + * {@code b.position()} through {@code b.position() + b.limit() -1 + * } should have the format of a valid class file as defined by * The Java™ Virtual Machine Specification. * * @param protectionDomain @@ -1158,7 +1158,7 @@ /** * Links the specified class. This (misleadingly named) method may be - * used by a class loader to link a class. If the class c has + * used by a class loader to link a class. If the class {@code c} has * already been linked, then this method simply returns. Otherwise, the * class is linked as described in the "Execution" chapter of * The Java™ Language Specification. @@ -1167,7 +1167,7 @@ * The class to link * * @throws NullPointerException - * If c is null. + * If {@code c} is {@code null}. * * @see #defineClass(String, byte[], int, int) */ @@ -1182,16 +1182,16 @@ * loading it if necessary. * *

    This method loads the class through the system class loader (see - * {@link #getSystemClassLoader()}). The Class object returned - * might have more than one ClassLoader associated with it. - * Subclasses of ClassLoader need not usually invoke this method, + * {@link #getSystemClassLoader()}). The {@code Class} object returned + * might have more than one {@code ClassLoader} associated with it. + * Subclasses of {@code ClassLoader} need not usually invoke this method, * because most class loaders need to override just {@link * #findClass(String)}.

    * * @param name * The binary name of the class * - * @return The Class object for the specified name + * @return The {@code Class} object for the specified {@code name} * * @throws ClassNotFoundException * If the class could not be found @@ -1222,12 +1222,12 @@ * Returns the class with the given binary name if this * loader has been recorded by the Java virtual machine as an initiating * loader of a class with that binary name. Otherwise - * null is returned. + * {@code null} is returned. * * @param name * The binary name of the class * - * @return The Class object, or null if the class has + * @return The {@code Class} object, or {@code null} if the class has * not been loaded * * @since 1.1 @@ -1245,7 +1245,7 @@ * class. * * @param c - * The Class object + * The {@code Class} object * * @param signers * The signers for the class @@ -1306,11 +1306,11 @@ * (images, audio, text, etc) that can be accessed by class code in a way * that is independent of the location of the code. * - *

    The name of a resource is a '/'-separated path name that + *

    The name of a resource is a '{@code /}'-separated path name that * identifies the resource. * *

    This method will first search the parent class loader for the - * resource; if the parent is null the path of the class loader + * resource; if the parent is {@code null} the path of the class loader * built-in to the virtual machine is searched. That failing, this method * will invoke {@link #findResource(String)} to find the resource.

    * @@ -1362,7 +1362,7 @@ * (images, audio, text, etc) that can be accessed by class code in a way * that is independent of the location of the code. * - *

    The name of a resource is a /-separated path name that + *

    The name of a resource is a {@code /}-separated path name that * identifies the resource. * *

    The delegation order for searching is described in the documentation @@ -1389,7 +1389,7 @@ * @param name * The resource name * - * @return An enumeration of {@link java.net.URL URL} objects for + * @return An enumeration of {@link java.net.URL URL} objects for * the resource. If no resources could be found, the enumeration * will be empty. Resources for which a {@code URL} cannot be * constructed, are in package that is not opened unconditionally, @@ -1505,7 +1505,7 @@ } /** - * Returns an enumeration of {@link java.net.URL URL} objects + * Returns an enumeration of {@link java.net.URL URL} objects * representing all the resources with the given name. Class loader * implementations should override this method to specify where to load * resources from. @@ -1520,7 +1520,7 @@ * @param name * The resource name * - * @return An enumeration of {@link java.net.URL URL} objects for + * @return An enumeration of {@link java.net.URL URL} objects for * the resource. If no resources could be found, the enumeration * will be empty. Resources for which a {@code URL} cannot be * constructed, are in a package that is not opened unconditionally, @@ -1594,7 +1594,7 @@ * @param name * The resource name * - * @return A {@link java.net.URL URL} to the resource; {@code + * @return A {@link java.net.URL URL} to the resource; {@code * null} if the resource could not be found, a URL could not be * constructed to locate the resource, the resource is in a package * that is not opened unconditionally or access to the resource is @@ -1609,8 +1609,8 @@ /** * Finds all resources of the specified name from the search path used to * load classes. The resources thus found are returned as an - * {@link java.util.Enumeration Enumeration} of {@link - * java.net.URL URL} objects. + * {@link java.util.Enumeration Enumeration} of {@link + * java.net.URL URL} objects. * *

    The search order is described in the documentation for {@link * #getSystemResource(String)}.

    @@ -1625,7 +1625,7 @@ * @param name * The resource name * - * @return An enumeration of {@link java.net.URL URL} objects for + * @return An enumeration of {@link java.net.URL URL} objects for * the resource. If no resources could be found, the enumeration * will be empty. Resources for which a {@code URL} cannot be * constructed, are in a package that is not opened unconditionally, @@ -1714,11 +1714,11 @@ /** * Returns the parent class loader for delegation. Some implementations may - * use null to represent the bootstrap class loader. This method - * will return null in such implementations if this class loader's + * use {@code null} to represent the bootstrap class loader. This method + * will return {@code null} in such implementations if this class loader's * parent is the bootstrap class loader. * - * @return The parent ClassLoader + * @return The parent {@code ClassLoader} * * @throws SecurityException * If a security manager is present, and the caller's class loader @@ -1785,7 +1785,7 @@ /** * Returns the system class loader for delegation. This is the default - * delegation parent for new ClassLoader instances, and is + * delegation parent for new {@code ClassLoader} instances, and is * typically the class loader used to start the application. * *

    This method is first invoked early in the runtime's startup @@ -1797,12 +1797,12 @@ *

    The default system class loader is an implementation-dependent * instance of this class. * - *

    If the system property "java.system.class.loader" is defined + *

    If the system property "{@code java.system.class.loader}" is defined * when this method is first invoked then the value of that property is * taken to be the name of a class that will be returned as the system * class loader. The class is loaded using the default system class loader * and must define a public constructor that takes a single parameter of - * type ClassLoader which is used as the delegation parent. An + * type {@code ClassLoader} which is used as the delegation parent. An * instance is then created using this constructor with the default system * class loader as the parameter. The resulting class loader is defined * to be the system class loader. During construction, the class loader @@ -1825,7 +1825,7 @@ * the application module path then the class path defaults to * the current working directory. * - * @return The system ClassLoader for delegation + * @return The system {@code ClassLoader} for delegation * * @throws SecurityException * If a security manager is present, and the caller's class loader @@ -1835,11 +1835,11 @@ * * @throws IllegalStateException * If invoked recursively during the construction of the class - * loader specified by the "java.system.class.loader" + * loader specified by the "{@code java.system.class.loader}" * property. * * @throws Error - * If the system property "java.system.class.loader" + * If the system property "{@code java.system.class.loader}" * is defined but the named class could not be loaded, the * provider class does not define the required constructor, or an * exception is thrown by that constructor when it is invoked. The @@ -2249,9 +2249,9 @@ /** * Returns the absolute path name of a native library. The VM invokes this * method to locate the native libraries that belong to classes loaded with - * this class loader. If this method returns null, the VM + * this class loader. If this method returns {@code null}, the VM * searches the library along the path specified as the - * "java.library.path" property. + * "{@code java.library.path}" property. * * @param libname * The library name @@ -2270,12 +2270,12 @@ /** * The inner class NativeLibrary denotes a loaded native library instance. * Every classloader contains a vector of loaded native libraries in the - * private field nativeLibraries. The native libraries loaded - * into the system are entered into the systemNativeLibraries + * private field {@code nativeLibraries}. The native libraries loaded + * into the system are entered into the {@code systemNativeLibraries} * vector. * *

    Every native library requires a particular version of JNI. This is - * denoted by the private jniVersion field. This field is set by + * denoted by the private {@code jniVersion} field. This field is set by * the VM when it loads the library, and used by the VM to pass the correct * version of JNI to the native methods.

    * @@ -2592,8 +2592,8 @@ * #setClassAssertionStatus(String, boolean)}. * * @param enabled - * true if classes loaded by this class loader will - * henceforth have assertions enabled by default, false + * {@code true} if classes loaded by this class loader will + * henceforth have assertions enabled by default, {@code false} * if they will have assertions disabled by default. * * @since 1.4 @@ -2614,16 +2614,16 @@ * any of its "subpackages". * *

    A subpackage of a package named p is any package whose name begins - * with "p.". For example, javax.swing.text is a - * subpackage of javax.swing, and both java.util and - * java.lang.reflect are subpackages of java. + * with "{@code p.}". For example, {@code javax.swing.text} is a + * subpackage of {@code javax.swing}, and both {@code java.util} and + * {@code java.lang.reflect} are subpackages of {@code java}. * *

    In the event that multiple package defaults apply to a given class, * the package default pertaining to the most specific package takes - * precedence over the others. For example, if javax.lang and - * javax.lang.reflect both have package defaults associated with + * precedence over the others. For example, if {@code javax.lang} and + * {@code javax.lang.reflect} both have package defaults associated with * them, the latter package default applies to classes in - * javax.lang.reflect. + * {@code javax.lang.reflect}. * *

    Package defaults take precedence over the class loader's default * assertion status, and may be overridden on a per-class basis by invoking @@ -2631,15 +2631,15 @@ * * @param packageName * The name of the package whose package default assertion status - * is to be set. A null value indicates the unnamed + * is to be set. A {@code null} value indicates the unnamed * package that is "current" * (see section 7.4.2 of * The Java™ Language Specification.) * * @param enabled - * true if classes loaded by this classloader and + * {@code true} if classes loaded by this classloader and * belonging to the named package or any of its subpackages will - * have assertions enabled by default, false if they will + * have assertions enabled by default, {@code false} if they will * have assertions disabled by default. * * @since 1.4 @@ -2670,8 +2670,8 @@ * assertion status is to be set. * * @param enabled - * true if the named class is to have assertions - * enabled when (and if) it is initialized, false if the + * {@code true} if the named class is to have assertions + * enabled when (and if) it is initialized, {@code false} if the * class is to have assertions disabled. * * @since 1.4 @@ -2687,7 +2687,7 @@ /** * Sets the default assertion status for this class loader to - * false and discards any package defaults or class assertion + * {@code false} and discards any package defaults or class assertion * status settings associated with the class loader. This method is * provided so that class loaders can be made to ignore any command line or * persistent assertion status settings and "start with a clean slate." diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/net/URLConnection.java --- a/jdk/src/java.base/share/classes/java/net/URLConnection.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/net/URLConnection.java Wed Jul 05 22:42:01 2017 +0200 @@ -30,8 +30,10 @@ import java.io.OutputStream; import java.security.PrivilegedAction; import java.util.Hashtable; +import java.util.concurrent.ConcurrentHashMap; import java.util.Date; import java.util.Iterator; +import java.util.Locale; import java.util.Objects; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; @@ -231,7 +233,7 @@ */ protected boolean allowUserInteraction = defaultAllowUserInteraction; - private static boolean defaultUseCaches = true; + private static volatile boolean defaultUseCaches = true; /** * If {@code true}, the protocol is allowed to use caching @@ -243,12 +245,18 @@ *

    * Its default value is the value given in the last invocation of the * {@code setDefaultUseCaches} method. + *

    + * The default setting may be overridden per protocol with + * {@link #setDefaultUseCaches(String,boolean)}. * * @see java.net.URLConnection#setUseCaches(boolean) * @see java.net.URLConnection#getUseCaches() * @see java.net.URLConnection#setDefaultUseCaches(boolean) */ - protected boolean useCaches = defaultUseCaches; + protected boolean useCaches; + + private static final ConcurrentHashMap defaultCaching = + new ConcurrentHashMap<>(); /** * Some protocols support skipping the fetching of the object unless @@ -460,6 +468,11 @@ */ protected URLConnection(URL url) { this.url = url; + if (url == null) { + this.useCaches = defaultUseCaches; + } else { + this.useCaches = getDefaultUseCaches(url.getProtocol()); + } } /** @@ -981,7 +994,8 @@ * is true, the connection is allowed to use whatever caches it can. * If false, caches are to be ignored. * The default value comes from DefaultUseCaches, which defaults to - * true. + * true. A default value can also be set per-protocol using + * {@link #setDefaultUseCaches(String,boolean)}. * * @param usecaches a {@code boolean} indicating whether * or not to allow caching @@ -1032,9 +1046,10 @@ * Returns the default value of a {@code URLConnection}'s * {@code useCaches} flag. *

    - * Ths default is "sticky", being a part of the static state of all + * This default is "sticky", being a part of the static state of all * URLConnections. This flag applies to the next, and all following - * URLConnections that are created. + * URLConnections that are created. This default value can be over-ridden + * per protocol using {@link #setDefaultUseCaches(String,boolean)} * * @return the default value of a {@code URLConnection}'s * {@code useCaches} flag. @@ -1046,7 +1061,8 @@ /** * Sets the default value of the {@code useCaches} field to the - * specified value. + * specified value. This default value can be over-ridden + * per protocol using {@link #setDefaultUseCaches(String,boolean)} * * @param defaultusecaches the new value. * @see #getDefaultUseCaches() @@ -1055,6 +1071,43 @@ defaultUseCaches = defaultusecaches; } + /** + * Sets the default value of the {@code useCaches} field for the named + * protocol to the given value. This value overrides any default setting + * set by {@link #setDefaultUseCaches(boolean)} for the given protocol. + * Successive calls to this method change the setting and affect the + * default value for all future connections of that protocol. The protocol + * name is case insensitive. + * + * @param protocol the protocol to set the default for + * @param defaultVal whether caching is enabled by default for the given protocol + * @since 9 + */ + public static void setDefaultUseCaches(String protocol, boolean defaultVal) { + protocol = protocol.toLowerCase(Locale.US); + defaultCaching.put(protocol, defaultVal); + } + + /** + * Returns the default value of the {@code useCaches} flag for the given protocol. If + * {@link #setDefaultUseCaches(String,boolean)} was called for the given protocol, + * then that value is returned. Otherwise, if {@link #setDefaultUseCaches(boolean)} + * was called, then that value is returned. If neither method was called, + * the return value is {@code true}. The protocol name is case insensitive. + * + * @param protocol the protocol whose defaultUseCaches setting is required + * @return the default value of the {@code useCaches} flag for the given protocol. + * @since 9 + */ + public static boolean getDefaultUseCaches(String protocol) { + Boolean protoDefault = defaultCaching.get(protocol.toLowerCase(Locale.US)); + if (protoDefault != null) { + return protoDefault.booleanValue(); + } else { + return defaultUseCaches; + } + } + /** * Sets the general request property. If a property with the key already * exists, overwrite its value with the new value. diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/Collections.java --- a/jdk/src/java.base/share/classes/java/util/Collections.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Collections.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4354,6 +4354,11 @@ private Object readResolve() { return EMPTY_SET; } + + @Override + public int hashCode() { + return 0; + } } /** @@ -4786,6 +4791,10 @@ public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } + @Override + public int hashCode() { + return Objects.hashCode(element); + } } /** @@ -4848,6 +4857,10 @@ public Spliterator spliterator() { return singletonSpliterator(element); } + @Override + public int hashCode() { + return 31 + Objects.hashCode(element); + } } /** @@ -4970,6 +4983,11 @@ BiFunction remappingFunction) { throw new UnsupportedOperationException(); } + + @Override + public int hashCode() { + return Objects.hashCode(k) ^ Objects.hashCode(v); + } } // Miscellaneous diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/Date.java --- a/jdk/src/java.base/share/classes/java/util/Date.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Date.java Wed Jul 05 22:42:01 2017 +0200 @@ -82,17 +82,19 @@ * well; for example, the time scale used by the satellite-based * global positioning system (GPS) is synchronized to UTC but is * not adjusted for leap seconds. An interesting source of - * further information is the U.S. Naval Observatory, particularly - * the Directorate of Time at: + * further information is the United States Naval Observatory (USNO): *

    - *     http://www.usno.navy.mil
    + *     http://www.usno.navy.mil/USNO
      * 
    *

    - * and their definitions of "Systems of Time" at: + * and the material regarding "Systems of Time" at: *

      *     http://www.usno.navy.mil/USNO/time/master-clock/systems-of-time
      * 
    *

    + * which has descriptions of various different time systems including + * UT, UT1, and UTC. + *

    * In all methods of class {@code Date} that accept or return * year, month, date, hours, minutes, and seconds values, the * following representations are used: diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/ImmutableCollections.java --- a/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +35,7 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; +import jdk.internal.vm.annotation.Stable; /** * Container class for immutable collections. Not part of the public API. @@ -105,6 +106,11 @@ return null; // but the compiler doesn't know this } + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } @@ -112,9 +118,26 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_LIST); } + + @Override + public boolean contains(Object o) { + Objects.requireNonNull(o); + return false; + } + + @Override + public boolean containsAll(Collection o) { + return o.isEmpty(); // implicit nullcheck of o + } + + @Override + public int hashCode() { + return 1; + } } static final class List1 extends AbstractImmutableList { + @Stable private final E e0; List1(E e0) { @@ -129,7 +152,6 @@ @Override public E get(int index) { Objects.checkIndex(index, 1); - // assert index == 0 return e0; } @@ -140,10 +162,22 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_LIST, e0); } + + @Override + public boolean contains(Object o) { + return o.equals(e0); // implicit nullcheck of o + } + + @Override + public int hashCode() { + return 31 + e0.hashCode(); + } } static final class List2 extends AbstractImmutableList { + @Stable private final E e0; + @Stable private final E e1; List2(E e0, E e1) { @@ -166,6 +200,17 @@ } } + @Override + public boolean contains(Object o) { + return o.equals(e0) || o.equals(e1); // implicit nullcheck of o + } + + @Override + public int hashCode() { + int hash = 31 + e0.hashCode(); + return 31 * hash + e1.hashCode(); + } + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } @@ -176,6 +221,7 @@ } static final class ListN extends AbstractImmutableList { + @Stable private final E[] elements; @SafeVarargs @@ -200,6 +246,25 @@ return elements[index]; } + @Override + public boolean contains(Object o) { + for (E e : elements) { + if (o.equals(e)) { // implicit nullcheck of o + return true; + } + } + return false; + } + + @Override + public int hashCode() { + int hash = 1; + for (E e : elements) { + hash = 31 * hash + e.hashCode(); + } + return hash; + } + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } @@ -238,7 +303,13 @@ @Override public boolean contains(Object o) { - return super.contains(Objects.requireNonNull(o)); + Objects.requireNonNull(o); + return false; + } + + @Override + public boolean containsAll(Collection o) { + return o.isEmpty(); // implicit nullcheck of o } @Override @@ -253,9 +324,15 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_SET); } + + @Override + public int hashCode() { + return 0; + } } static final class Set1 extends AbstractImmutableSet { + @Stable private final E e0; Set1(E e0) { @@ -269,7 +346,7 @@ @Override public boolean contains(Object o) { - return super.contains(Objects.requireNonNull(o)); + return o.equals(e0); // implicit nullcheck of o } @Override @@ -284,17 +361,21 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_SET, e0); } + + @Override + public int hashCode() { + return e0.hashCode(); + } } static final class Set2 extends AbstractImmutableSet { - private final E e0; - private final E e1; + @Stable + final E e0; + @Stable + final E e1; Set2(E e0, E e1) { - Objects.requireNonNull(e0); - Objects.requireNonNull(e1); - - if (e0.equals(e1)) { + if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0 throw new IllegalArgumentException("duplicate element: " + e0); } @@ -314,7 +395,12 @@ @Override public boolean contains(Object o) { - return super.contains(Objects.requireNonNull(o)); + return o.equals(e0) || o.equals(e1); // implicit nullcheck of o + } + + @Override + public int hashCode() { + return e0.hashCode() + e1.hashCode(); } @Override @@ -358,8 +444,10 @@ * @param the element type */ static final class SetN extends AbstractImmutableSet { - private final E[] elements; - private final int size; + @Stable + final E[] elements; + @Stable + final int size; @SafeVarargs @SuppressWarnings("unchecked") @@ -368,8 +456,8 @@ 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); + E e = input[i]; + int idx = probe(e); // implicit nullcheck of e if (idx >= 0) { throw new IllegalArgumentException("duplicate element: " + e); } else { @@ -385,8 +473,7 @@ @Override public boolean contains(Object o) { - Objects.requireNonNull(o); - return probe(o) >= 0; + return probe(o) >= 0; // implicit nullcheck of o } @Override @@ -414,8 +501,21 @@ }; } + @Override + public int hashCode() { + int h = 0; + for (E e : elements) { + if (e != null) { + h += e.hashCode(); + } + } + return h; + } + // returns index at which element is present; or if absent, - // (-i - 1) where i is location where element should be inserted + // (-i - 1) where i is location where element should be inserted. + // Callers are relying on this method to perform an implicit nullcheck + // of pe private int probe(Object pe) { int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length); while (true) { @@ -481,12 +581,14 @@ @Override public boolean containsKey(Object o) { - return super.containsKey(Objects.requireNonNull(o)); + Objects.requireNonNull(o); + return false; } @Override public boolean containsValue(Object o) { - return super.containsValue(Objects.requireNonNull(o)); + Objects.requireNonNull(o); + return false; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { @@ -496,10 +598,17 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_MAP); } + + @Override + public int hashCode() { + return 0; + } } static final class Map1 extends AbstractImmutableMap { + @Stable private final K k0; + @Stable private final V v0; Map1(K k0, V v0) { @@ -514,12 +623,12 @@ @Override public boolean containsKey(Object o) { - return super.containsKey(Objects.requireNonNull(o)); + return o.equals(k0); // implicit nullcheck of o } @Override public boolean containsValue(Object o) { - return super.containsValue(Objects.requireNonNull(o)); + return o.equals(v0); // implicit nullcheck of o } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { @@ -529,6 +638,11 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_MAP, k0, v0); } + + @Override + public int hashCode() { + return k0.hashCode() ^ v0.hashCode(); + } } /** @@ -541,12 +655,13 @@ * @param the value type */ static final class MapN extends AbstractImmutableMap { - private final Object[] table; // pairs of key, value - private final int size; // number of pairs + @Stable + final Object[] table; // pairs of key, value + @Stable + final int size; // number of pairs MapN(Object... input) { - Objects.requireNonNull(input); - if ((input.length & 1) != 0) { + if ((input.length & 1) != 0) { // implicit nullcheck of input throw new InternalError("length is odd"); } size = input.length >> 1; @@ -573,12 +688,30 @@ @Override public boolean containsKey(Object o) { - return probe(Objects.requireNonNull(o)) >= 0; + return probe(o) >= 0; // implicit nullcheck of o } @Override public boolean containsValue(Object o) { - return super.containsValue(Objects.requireNonNull(o)); + for (int i = 1; i < table.length; i += 2) { + Object v = table[i]; + if (v != null && o.equals(v)) { // implicit nullcheck of o + return true; + } + } + return false; + } + + @Override + public int hashCode() { + int hash = 0; + for (int i = 0; i < table.length; i += 2) { + Object k = table[i]; + if (k != null) { + hash += k.hashCode() ^ table[i + 1].hashCode(); + } + } + return hash; } @Override @@ -638,7 +771,9 @@ } // returns index at which the probe key is present; or if absent, - // (-i - 1) where i is location where element should be inserted + // (-i - 1) where i is location where element should be inserted. + // Callers are relying on this method to perform an implicit nullcheck + // of pk. private int probe(Object pk) { int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1; while (true) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/KeyValueHolder.java --- a/jdk/src/java.base/share/classes/java/util/KeyValueHolder.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/KeyValueHolder.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package java.util; +import jdk.internal.vm.annotation.Stable; + /** * An immutable container for a key and a value, suitable for use * in creating and populating {@code Map} instances. @@ -48,7 +50,9 @@ * @since 9 */ final class KeyValueHolder implements Map.Entry { + @Stable final K key; + @Stable final V value; KeyValueHolder(K k, V v) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/List.java --- a/jdk/src/java.base/share/classes/java/util/List.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/List.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1027,8 +1027,7 @@ @SafeVarargs @SuppressWarnings("varargs") static List of(E... elements) { - Objects.requireNonNull(elements); - switch (elements.length) { + switch (elements.length) { // implicit null check of elements case 0: return ImmutableCollections.List0.instance(); case 1: diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/Map.java --- a/jdk/src/java.base/share/classes/java/util/Map.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Map.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1602,8 +1602,7 @@ @SafeVarargs @SuppressWarnings("varargs") static Map ofEntries(Entry... entries) { - Objects.requireNonNull(entries); - if (entries.length == 0) { + if (entries.length == 0) { // implicit null check of entries return ImmutableCollections.Map0.instance(); } else if (entries.length == 1) { return new ImmutableCollections.Map1<>(entries[0].getKey(), diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/java/util/Set.java --- a/jdk/src/java.base/share/classes/java/util/Set.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Set.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -689,8 +689,7 @@ @SafeVarargs @SuppressWarnings("varargs") static Set of(E... elements) { - Objects.requireNonNull(elements); - switch (elements.length) { + switch (elements.length) { // implicit null check of elements case 0: return ImmutableCollections.Set0.instance(); case 1: diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.PrintStream; +import java.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; +import static java.util.stream.Collectors.*; + +/** + * A Builder to compute ModuleHashes from a given configuration + */ +public class ModuleHashesBuilder { + private final Configuration configuration; + private final Set hashModuleCandidates; + + /** + * Constructs a ModuleHashesBuilder that finds the packaged modules + * from the location of ModuleReference found from the given Configuration. + * + * @param config Configuration for building module hashes + * @param modules the candidate modules to be hashed + */ + public ModuleHashesBuilder(Configuration config, Set modules) { + this.configuration = config; + this.hashModuleCandidates = modules; + } + + /** + * Returns a map of a module M to ModuleHashes for the modules + * that depend upon M directly or indirectly. + * + * The key for each entry in the returned map is a module M that has + * no outgoing edges to any of the candidate modules to be hashed + * i.e. M is a leaf node in a connected subgraph containing M and + * other candidate modules from the module graph filtering + * the outgoing edges from M to non-candidate modules. + */ + public Map computeHashes(Set roots) { + // build a graph containing the the packaged modules and + // its transitive dependences matching --hash-modules + Graph.Builder builder = new Graph.Builder<>(); + Deque deque = new ArrayDeque<>(configuration.modules()); + Set visited = new HashSet<>(); + while (!deque.isEmpty()) { + ResolvedModule rm = deque.pop(); + if (!visited.contains(rm)) { + visited.add(rm); + builder.addNode(rm.name()); + for (ResolvedModule dm : rm.reads()) { + if (!visited.contains(dm)) { + deque.push(dm); + } + builder.addEdge(rm.name(), dm.name()); + } + } + } + + // each node in a transposed graph is a matching packaged module + // in which the hash of the modules that depend upon it is recorded + Graph transposedGraph = builder.build().transpose(); + + // traverse the modules in topological order that will identify + // the modules to record the hashes - it is the first matching + // module and has not been hashed during the traversal. + Set mods = new HashSet<>(); + Map hashes = new HashMap<>(); + builder.build() + .orderedNodes() + .filter(mn -> roots.contains(mn) && !mods.contains(mn)) + .forEach(mn -> { + // Compute hashes of the modules that depend on mn directly and + // indirectly excluding itself. + Set ns = transposedGraph.dfs(mn) + .stream() + .filter(n -> !n.equals(mn) && hashModuleCandidates.contains(n)) + .collect(toSet()); + mods.add(mn); + mods.addAll(ns); + + if (!ns.isEmpty()) { + Map moduleToPath = ns.stream() + .collect(toMap(Function.identity(), this::moduleToPath)); + hashes.put(mn, ModuleHashes.generate(moduleToPath, "SHA-256")); + } + }); + return hashes; + } + + private Path moduleToPath(String name) { + ResolvedModule rm = configuration.findModule(name).orElseThrow( + () -> new InternalError("Selected module " + name + " not on module path")); + + URI uri = rm.reference().location().get(); + Path path = Paths.get(uri); + String fn = path.getFileName().toString(); + if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) { + throw new UnsupportedOperationException(path + " is not a modular JAR or jmod file"); + } + return path; + } + + /* + * Utilty class + */ + static class Graph { + private final Set nodes; + private final Map> edges; + + public Graph(Set nodes, Map> edges) { + this.nodes = Collections.unmodifiableSet(nodes); + this.edges = Collections.unmodifiableMap(edges); + } + + public Set nodes() { + return nodes; + } + + public Map> edges() { + return edges; + } + + public Set adjacentNodes(T u) { + return edges.get(u); + } + + public boolean contains(T u) { + return nodes.contains(u); + } + + /** + * Returns nodes sorted in topological order. + */ + public Stream orderedNodes() { + TopoSorter sorter = new TopoSorter<>(this); + return sorter.result.stream(); + } + + /** + * Traverse this graph and performs the given action in topological order + */ + public void ordered(Consumer action) { + TopoSorter sorter = new TopoSorter<>(this); + sorter.ordered(action); + } + + /** + * Traverses this graph and performs the given action in reverse topological order + */ + public void reverse(Consumer action) { + TopoSorter sorter = new TopoSorter<>(this); + sorter.reverse(action); + } + + /** + * Returns a transposed graph from this graph + */ + public Graph transpose() { + Builder builder = new Builder<>(); + nodes.stream().forEach(builder::addNode); + // reverse edges + edges.keySet().forEach(u -> { + edges.get(u).stream() + .forEach(v -> builder.addEdge(v, u)); + }); + return builder.build(); + } + + /** + * Returns all nodes reachable from the given root. + */ + public Set dfs(T root) { + return dfs(Set.of(root)); + } + + /** + * Returns all nodes reachable from the given set of roots. + */ + public Set dfs(Set roots) { + Deque deque = new LinkedList<>(roots); + Set visited = new HashSet<>(); + while (!deque.isEmpty()) { + T u = deque.pop(); + if (!visited.contains(u)) { + visited.add(u); + if (contains(u)) { + adjacentNodes(u).stream() + .filter(v -> !visited.contains(v)) + .forEach(deque::push); + } + } + } + return visited; + } + + public void printGraph(PrintStream out) { + out.println("graph for " + nodes); + nodes.stream() + .forEach(u -> adjacentNodes(u).stream() + .forEach(v -> out.format(" %s -> %s%n", u, v))); + } + + static class Builder { + final Set nodes = new HashSet<>(); + final Map> edges = new HashMap<>(); + + public void addNode(T node) { + if (nodes.contains(node)) { + return; + } + nodes.add(node); + edges.computeIfAbsent(node, _e -> new HashSet<>()); + } + + public void addEdge(T u, T v) { + addNode(u); + addNode(v); + edges.get(u).add(v); + } + + public Graph build() { + return new Graph(nodes, edges); + } + } + } + + /** + * Topological sort + */ + private static class TopoSorter { + final Deque result = new LinkedList<>(); + final Deque nodes; + final Graph graph; + + TopoSorter(Graph graph) { + this.graph = graph; + this.nodes = new LinkedList<>(graph.nodes); + sort(); + } + + public void ordered(Consumer action) { + result.iterator().forEachRemaining(action); + } + + public void reverse(Consumer action) { + result.descendingIterator().forEachRemaining(action); + } + + private void sort() { + Deque visited = new LinkedList<>(); + Deque done = new LinkedList<>(); + T node; + while ((node = nodes.poll()) != null) { + if (!visited.contains(node)) { + visit(node, visited, done); + } + } + } + + private void visit(T node, Deque visited, Deque done) { + if (visited.contains(node)) { + if (!done.contains(node)) { + throw new IllegalArgumentException("Cyclic detected: " + + node + " " + graph.edges().get(node)); + } + return; + } + visited.add(node); + graph.edges().get(node).stream() + .forEach(x -> visit(x, visited, done)); + done.add(node); + result.addLast(node); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/native/libnet/net_util.c --- a/jdk/src/java.base/share/native/libnet/net_util.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/native/libnet/net_util.c Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,10 +64,10 @@ preferIPv4Stack = (*env)->CallStaticBooleanMethod(env, iCls, mid, s); /* - Since we have initialized and loaded the Socket library we will - check now to whether we have IPv6 on this platform and if the - supporting socket APIs are available - */ + * Since we have initialized and loaded the socket library we will + * check now whether we have IPv6 on this platform and if the + * supporting socket APIs are available + */ IPv6_available = IPv6_supported() & (!preferIPv4Stack); /* check if SO_REUSEPORT is supported on this platform */ @@ -120,16 +120,16 @@ return JNI_TRUE; } -int getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) { +jboolean getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) { jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); - CHECK_NULL_RETURN(holder, -1); + CHECK_NULL_RETURN(holder, JNI_FALSE); return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID); } -int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { +unsigned int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); - CHECK_NULL_RETURN(holder, -1); - return (*env)->GetIntField(env, holder, ia6_scopeidID); + CHECK_NULL_RETURN(holder, 0); + return (unsigned int)(*env)->GetIntField(env, holder, ia6_scopeidID); } jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) { @@ -201,11 +201,10 @@ } JNIEXPORT jobject JNICALL -NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { +NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port) { jobject iaObj; - if (him->sa_family == AF_INET6) { - struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; - jbyte *caddr = (jbyte *)&(him6->sin6_addr); + if (sa->sa.sa_family == AF_INET6) { + jbyte *caddr = (jbyte *)&sa->sa6.sin6_addr; if (NET_IsIPv4Mapped(caddr)) { int address; iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); @@ -214,42 +213,35 @@ setInetAddress_addr(env, iaObj, address); setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); } else { - jint scope; jboolean ret; iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); CHECK_NULL_RETURN(iaObj, NULL); - ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr)); + ret = setInet6Address_ipaddress(env, iaObj, (char *)&sa->sa6.sin6_addr); if (ret == JNI_FALSE) return NULL; setInetAddress_family(env, iaObj, java_net_InetAddress_IPv6); - scope = getScopeID(him); - setInet6Address_scopeid(env, iaObj, scope); + setInet6Address_scopeid(env, iaObj, sa->sa6.sin6_scope_id); } - *port = ntohs(him6->sin6_port); + *port = ntohs(sa->sa6.sin6_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); + setInetAddress_addr(env, iaObj, ntohl(sa->sa4.sin_addr.s_addr)); + *port = ntohs(sa->sa4.sin_port); } return iaObj; } -JNIEXPORT jint JNICALL -NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) +JNIEXPORT jboolean JNICALL +NET_SockaddrEqualsInetAddress(JNIEnv *env, SOCKETADDRESS *sa, jobject iaObj) { - jint family = AF_INET; - - family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ? - AF_INET : AF_INET6; - if (him->sa_family == AF_INET6) { - struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; - jbyte *caddrNew = (jbyte *)&(him6->sin6_addr); + jint family = getInetAddress_family(env, iaObj) == + java_net_InetAddress_IPv4 ? AF_INET : AF_INET6; + if (sa->sa.sa_family == AF_INET6) { + jbyte *caddrNew = (jbyte *)&sa->sa6.sin6_addr; if (NET_IsIPv4Mapped(caddrNew)) { - int addrNew; - int addrCur; + int addrNew, addrCur; if (family == AF_INET6) { return JNI_FALSE; } @@ -262,26 +254,24 @@ } } else { jbyte caddrCur[16]; - int scope; - if (family == AF_INET) { return JNI_FALSE; } - scope = getInet6Address_scopeid(env, iaObj); getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); - if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { + if (NET_IsEqual(caddrNew, caddrCur) && + sa->sa6.sin6_scope_id == getInet6Address_scopeid(env, iaObj)) + { 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); + addrNew = ntohl(sa->sa4.sin_addr.s_addr); addrCur = getInetAddress_addr(env, iaObj); if (addrNew == addrCur) { return JNI_TRUE; @@ -291,6 +281,15 @@ } } +JNIEXPORT jint JNICALL +NET_GetPortFromSockaddr(SOCKETADDRESS *sa) { + if (sa->sa.sa_family == AF_INET6) { + return ntohs(sa->sa6.sin6_port); + } else { + return ntohs(sa->sa4.sin_port); + } +} + unsigned short in_cksum(unsigned short *addr, int len) { int nleft = len; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/share/native/libnet/net_util.h --- a/jdk/src/java.base/share/native/libnet/net_util.h Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/share/native/libnet/net_util.h Wed Jul 05 22:42:01 2017 +0200 @@ -63,8 +63,8 @@ */ extern jobject getInet6Address_scopeifname(JNIEnv *env, jobject ia6Obj); extern jboolean setInet6Address_scopeifname(JNIEnv *env, jobject ia6Obj, jobject scopeifname); -extern int getInet6Address_scopeid_set(JNIEnv *env, jobject ia6Obj); -extern int getInet6Address_scopeid(JNIEnv *env, jobject ia6Obj); +extern jboolean getInet6Address_scopeid_set(JNIEnv *env, jobject ia6Obj); +extern unsigned int getInet6Address_scopeid(JNIEnv *env, jobject ia6Obj); extern jboolean setInet6Address_scopeid(JNIEnv *env, jobject ia6Obj, int scopeid); extern jboolean getInet6Address_ipaddress(JNIEnv *env, jobject ia6Obj, char *dest); extern jboolean setInet6Address_ipaddress(JNIEnv *env, jobject ia6Obj, char *address); @@ -132,24 +132,41 @@ JNIEXPORT jint JNICALL reuseport_available(); +/** + * This function will fill a SOCKETADDRESS structure from an InetAddress + * object. + * + * The parameter 'sa' must point to valid storage of size + * 'sizeof(SOCKETADDRESS)'. + * + * The parameter 'len' is a pointer to an int and is used for returning + * the actual sockaddr length, e.g. 'sizeof(struct sockaddr_in)' or + * 'sizeof(struct sockaddr_in6)'. + * + * If the type of the InetAddress object is IPv6, the function will fill a + * sockaddr_in6 structure. IPv6 must be available in that case, otherwise an + * exception is thrown. + * In the case of an IPv4 InetAddress, when IPv6 is available and + * v4MappedAddress is TRUE, this method will fill a sockaddr_in6 structure + * containing an IPv4 mapped IPv6 address. Otherwise a sockaddr_in + * structure will be filled. + */ JNIEXPORT int JNICALL NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, - struct sockaddr *him, int *len, + SOCKETADDRESS *sa, int *len, jboolean v4MappedAddress); JNIEXPORT jobject JNICALL -NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port); +NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port); void platformInit(); void parseExclusiveBindProperty(JNIEnv *env); -void NET_SetTrafficClass(struct sockaddr *him, int trafficClass); +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(SOCKETADDRESS *sa); -JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him); - -JNIEXPORT jint JNICALL -NET_SockaddrEqualsInetAddress(JNIEnv *env,struct sockaddr *him, jobject iaObj); +JNIEXPORT jboolean JNICALL +NET_SockaddrEqualsInetAddress(JNIEnv *env, SOCKETADDRESS *sa, jobject iaObj); int NET_IsIPv4Mapped(jbyte* caddr); @@ -172,7 +189,7 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, int len); JNIEXPORT int JNICALL -NET_Bind(int fd, struct sockaddr *him, int len); +NET_Bind(int fd, SOCKETADDRESS *sa, int len); JNIEXPORT int JNICALL NET_MapSocketOption(jint cmd, int *level, int *optname); @@ -183,10 +200,6 @@ JNIEXPORT jint JNICALL NET_EnableFastTcpLoopback(int fd); -int getScopeID(struct sockaddr *); - -int cmpScopeID(unsigned int, struct sockaddr *); - unsigned short in_cksum(unsigned short *addr, int len); jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -211,7 +211,8 @@ { int port; int index = (family == AF_INET) ? i++ : j++; - jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port); + jobject o = NET_SockaddrToInetAddress(env, + (SOCKETADDRESS *)iter->ifa_addr, &port); if (!o) { freeifaddrs(ifa); if (!(*env)->ExceptionCheck(env)) diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnet/NetworkInterface.c --- a/jdk/src/java.base/unix/native/libnet/NetworkInterface.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnet/NetworkInterface.c Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -791,7 +791,7 @@ int sock; sock = openSocket(env, AF_INET); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { + if (sock < 0) { return NULL; } @@ -809,7 +809,7 @@ // so we have to call ipv6_available() if (ipv6_available()) { sock = openSocket(env, AF_INET6); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { + if (sock < 0) { freeif(ifs); return NULL; } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -99,7 +99,7 @@ CHECK_NULL_RETURN(i_class, NULL); } - return ( (*env)->NewObject(env, i_class, i_ctrID, i) ); + return (*env)->NewObject(env, i_class, i_ctrID, i); } /* @@ -118,10 +118,9 @@ CHECK_NULL_RETURN(b_class, NULL); } - return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) ); + return (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b != 0)); } - /* * Returns the fd for a PlainDatagramSocketImpl or -1 * if closed. @@ -134,7 +133,6 @@ return (*env)->GetIntField(env, fdObj, IO_fd_fdID); } - /* * Class: java_net_PlainDatagramSocketImpl * Method: init @@ -166,7 +164,6 @@ initInetAddressIDs(env); JNU_CHECK_EXCEPTION(env); Java_java_net_NetworkInterface_init(env, 0); - } /* @@ -176,13 +173,13 @@ */ JNIEXPORT void JNICALL Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, - jint localport, jobject iaObj) { + jint localport, jobject iaObj) { /* fdObj is the FileDescriptor field on this */ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); /* fd is an int field on fdObj */ int fd; int len = 0; - SOCKETADDRESS him; + SOCKETADDRESS sa; socklen_t slen = sizeof(SOCKETADDRESS); if (IS_NULL(fdObj)) { @@ -199,12 +196,13 @@ } /* bind */ - if (NET_InetAddressToSockaddr(env, iaObj, localport, &him.sa, &len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len, + JNI_TRUE) != 0) { return; } - setDefaultScopeID(env, &him.sa); + setDefaultScopeID(env, &sa.sa); - if (NET_Bind(fd, &him.sa, len) < 0) { + if (NET_Bind(fd, &sa, len) < 0) { if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || errno == EPERM || errno == EACCES) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException", @@ -221,13 +219,13 @@ /* Now that we're a connected socket, let's extract the port number * that the system chose for us and store it in the Socket object. */ - if (getsockname(fd, &him.sa, &slen) == -1) { + if (getsockname(fd, &sa.sa, &slen) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); return; } - localport = NET_GetPortFromSockaddr(&him.sa); + localport = NET_GetPortFromSockaddr(&sa); (*env)->SetIntField(env, this, pdsi_localPortID, localport); } else { @@ -263,7 +261,8 @@ return; } - if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr.sa, &len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr, &len, + JNI_TRUE) != 0) { return; } @@ -290,6 +289,9 @@ #if defined(__linux__) || defined(_ALLBSD_SOURCE) SOCKETADDRESS addr; socklen_t len; +#if defined(__linux__) + int localPort = 0; +#endif #endif if (IS_NULL(fdObj)) { @@ -298,32 +300,31 @@ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); #if defined(__linux__) || defined(_ALLBSD_SOURCE) - memset(&addr, 0, sizeof(addr)); - if (ipv6_available()) { - addr.sa6.sin6_family = AF_UNSPEC; - len = sizeof(struct sockaddr_in6); - } else { - addr.sa4.sin_family = AF_UNSPEC; - len = sizeof(struct sockaddr_in); - } - NET_Connect(fd, &addr.sa, len); + memset(&addr, 0, sizeof(addr)); + if (ipv6_available()) { + addr.sa6.sin6_family = AF_UNSPEC; + len = sizeof(struct sockaddr_in6); + } else { + addr.sa4.sin_family = AF_UNSPEC; + len = sizeof(struct sockaddr_in); + } + NET_Connect(fd, &addr.sa, len); -#ifdef __linux__ - int localPort = 0; - if (getsockname(fd, &addr.sa, &len) == -1) - return; +#if defined(__linux__) + if (getsockname(fd, &addr.sa, &len) == -1) + return; - localPort = NET_GetPortFromSockaddr(&addr.sa); - if (localPort == 0) { - localPort = (*env)->GetIntField(env, this, pdsi_localPortID); - if (addr.sa.sa_family == AF_INET6) { - addr.sa6.sin6_port = htons(localPort); - } else { - addr.sa4.sin_port = htons(localPort); - } + localPort = NET_GetPortFromSockaddr(&addr); + if (localPort == 0) { + localPort = (*env)->GetIntField(env, this, pdsi_localPortID); + if (addr.sa.sa_family == AF_INET6) { + addr.sa6.sin6_port = htons(localPort); + } else { + addr.sa4.sin_port = htons(localPort); + } - NET_Bind(fd, &addr.sa, len); - } + NET_Bind(fd, &addr, len); + } #endif #else @@ -355,8 +356,9 @@ /* The fdObj'fd */ jint fd; - SOCKETADDRESS rmtaddr, *rmtaddrP = &rmtaddr; - int len; + SOCKETADDRESS rmtaddr; + struct sockaddr *rmtaddrP = 0; + int len = 0; if (IS_NULL(fdObj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -382,15 +384,14 @@ packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID); packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID); - if (connected) { - /* arg to NET_Sendto () null in this case */ - len = 0; - rmtaddrP = 0; - } else { + // arg to NET_Sendto() null, if connected + if (!connected) { packetPort = (*env)->GetIntField(env, packet, dp_portID); - if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, &rmtaddr.sa, &len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, &rmtaddr, + &len, JNI_TRUE) != 0) { return; } + rmtaddrP = &rmtaddr.sa; } setDefaultScopeID(env, &rmtaddr.sa); @@ -427,7 +428,7 @@ (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen, (jbyte *)fullPacket); if (trafficClass != 0 && ipv6_available()) { - NET_SetTrafficClass(&rmtaddr.sa, trafficClass); + NET_SetTrafficClass(&rmtaddr, trafficClass); } /* @@ -437,8 +438,7 @@ * ECONNREFUSED indicating that an ICMP port unreachable has * received. */ - ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0, - (struct sockaddr *)rmtaddrP, len); + ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0, rmtaddrP, len); if (ret < 0) { if (errno == ECONNREFUSED) { @@ -510,7 +510,7 @@ #ifdef __solaris__ if (errno == ECONNREFUSED) { int orig_errno = errno; - (void) recv(fd, buf, 1, 0); + recv(fd, buf, 1, 0); errno = orig_errno; } #endif @@ -528,7 +528,7 @@ return 0; } - iaObj = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &rmtaddr, &port); family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ? AF_INET : AF_INET6; if (family == AF_INET) { /* this API can't handle IPV6 addresses */ @@ -676,18 +676,18 @@ */ packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr.sa, packetAddress)) { + if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr, packetAddress)) { /* force a new InetAddress to be created */ packetAddress = NULL; } } if (packetAddress == NULL) { - packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port); + packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr, &port); /* stuff the new Inetaddress in the packet */ (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); } else { /* only get the new port number */ - port = NET_GetPortFromSockaddr(&rmtaddr.sa); + port = NET_GetPortFromSockaddr(&rmtaddr); } /* and fill in the data, remote address/port and such */ (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, @@ -857,18 +857,19 @@ */ packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr.sa, packetAddress)) { + if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr, + packetAddress)) { /* force a new InetAddress to be created */ packetAddress = NULL; } } if (packetAddress == NULL) { - packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port); + packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr, &port); /* stuff the new Inetaddress in the packet */ (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); } else { /* only get the new port number */ - port = NET_GetPortFromSockaddr(&rmtaddr.sa); + port = NET_GetPortFromSockaddr(&rmtaddr); } /* and fill in the data, remote address/port and such */ (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, @@ -1040,6 +1041,7 @@ /* * We need an ipv4 address here */ + in.s_addr = 0; for (i = 0; i < len; i++) { addr = (*env)->GetObjectArrayElement(env, addrArray, i); if (getInetAddress_family(env, addr) == java_net_InetAddress_IPv4) { @@ -1049,7 +1051,7 @@ } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - (const char*)&in, sizeof(in)) < 0) { + (const char *)&in, sizeof(in)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); } @@ -1670,17 +1672,17 @@ */ if (opt == java_net_SocketOptions_SO_BINDADDR) { /* find out local IP address */ - SOCKETADDRESS him; + SOCKETADDRESS sa; socklen_t len = sizeof(SOCKETADDRESS); int port; jobject iaObj; - if (getsockname(fd, &him.sa, &len) == -1) { + if (getsockname(fd, &sa.sa, &len) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); return NULL; } - iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &sa, &port); return iaObj; } @@ -1969,6 +1971,7 @@ mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj)); #ifdef __linux__ mname.imr_address.s_addr = htonl(getInetAddress_addr(env, addr)); + mname.imr_ifindex = 0; #else mname.imr_interface.s_addr = htonl(getInetAddress_addr(env, addr)); #endif @@ -2023,7 +2026,7 @@ #ifdef __linux__ mname.imr_address.s_addr = in.s_addr; - + mname.imr_ifindex = 0; #else mname.imr_interface.s_addr = in.s_addr; #endif diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -244,7 +244,7 @@ /* fd is an int field on iaObj */ jint fd; - SOCKETADDRESS him; + SOCKETADDRESS sa; /* The result of the connection */ int connect_rv = -1; @@ -260,17 +260,18 @@ } /* connect */ - if (NET_InetAddressToSockaddr(env, iaObj, port, &him.sa, &len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len, + JNI_TRUE) != 0) { return; } - setDefaultScopeID(env, &him.sa); + setDefaultScopeID(env, &sa.sa); if (trafficClass != 0 && ipv6_available()) { - NET_SetTrafficClass(&him.sa, trafficClass); + NET_SetTrafficClass(&sa, trafficClass); } if (timeout <= 0) { - connect_rv = NET_Connect(fd, &him.sa, len); + connect_rv = NET_Connect(fd, &sa.sa, len); #ifdef __solaris__ if (connect_rv == -1 && errno == EINPROGRESS ) { @@ -319,7 +320,7 @@ SET_NONBLOCKING(fd); /* no need to use NET_Connect as non-blocking */ - connect_rv = connect(fd, &him.sa, len); + connect_rv = connect(fd, &sa.sa, len); /* connection not established immediately */ if (connect_rv != 0) { @@ -467,11 +468,11 @@ * that the system chose for us and store it in the Socket object. */ socklen_t slen = sizeof(SOCKETADDRESS); - if (getsockname(fd, &him.sa, &slen) == -1) { + if (getsockname(fd, &sa.sa, &slen) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); } else { - localport = NET_GetPortFromSockaddr(&him.sa); + localport = NET_GetPortFromSockaddr(&sa); (*env)->SetIntField(env, this, psi_localportID, localport); } } @@ -490,8 +491,8 @@ jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); /* fd is an int field on fdObj */ int fd; - int len; - SOCKETADDRESS him; + int len = 0; + SOCKETADDRESS sa; if (IS_NULL(fdObj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -506,13 +507,13 @@ } /* bind */ - if (NET_InetAddressToSockaddr(env, iaObj, localport, &him.sa, + if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len, JNI_TRUE) != 0) { return; } - setDefaultScopeID(env, &him.sa); + setDefaultScopeID(env, &sa.sa); - if (NET_Bind(fd, &him.sa, len) < 0) { + if (NET_Bind(fd, &sa, len) < 0) { if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || errno == EPERM || errno == EACCES) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException", @@ -533,12 +534,12 @@ /* Now that we're a connected socket, let's extract the port number * that the system chose for us and store it in the Socket object. */ - if (getsockname(fd, &him.sa, &slen) == -1) { + if (getsockname(fd, &sa.sa, &slen) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); return; } - localport = NET_GetPortFromSockaddr(&him.sa); + localport = NET_GetPortFromSockaddr(&sa); (*env)->SetIntField(env, this, psi_localportID, localport); } else { (*env)->SetIntField(env, this, psi_localportID, localport); @@ -606,7 +607,7 @@ /* accepted fd */ jint newfd; - SOCKETADDRESS him; + SOCKETADDRESS sa; socklen_t slen = sizeof(SOCKETADDRESS); if (IS_NULL(fdObj)) { @@ -661,7 +662,7 @@ return; } - newfd = NET_Accept(fd, &him.sa, &slen); + newfd = NET_Accept(fd, &sa.sa, &slen); /* connection accepted */ if (newfd >= 0) { @@ -709,7 +710,7 @@ /* * fill up the remote peer port and address in the new socket structure. */ - socketAddressObj = NET_SockaddrToInetAddress(env, &him.sa, &port); + socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); if (socketAddressObj == NULL) { /* should be pending exception */ close(newfd); @@ -944,19 +945,19 @@ * SO_BINDADDR isn't a socket option */ if (cmd == java_net_SocketOptions_SO_BINDADDR) { - SOCKETADDRESS him; + SOCKETADDRESS sa; socklen_t len = sizeof(SOCKETADDRESS); int port; jobject iaObj; jclass iaCntrClass; jfieldID iaFieldID; - if (getsockname(fd, &him.sa, &len) < 0) { + if (getsockname(fd, &sa.sa, &len) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); return -1; } - iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &sa, &port); CHECK_NULL_RETURN(iaObj, -1); iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnet/net_util_md.c --- a/jdk/src/java.base/unix/native/libnet/net_util_md.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c Wed Jul 05 22:42:01 2017 +0200 @@ -234,29 +234,6 @@ } return kernelV24; } - -int getScopeID (struct sockaddr *him) { - struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him; - return hext->sin6_scope_id; -} - -int cmpScopeID (unsigned int scope, struct sockaddr *him) { - struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him; - return hext->sin6_scope_id == scope; -} - -#else - -int getScopeID (struct sockaddr *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; - return him6->sin6_scope_id == scope; -} - #endif void @@ -775,30 +752,32 @@ return 0; } -/* In the case of an IPv4 Inetaddress this method will return an - * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE. - * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress. -*/ +/** + * See net_util.h for documentation + */ JNIEXPORT int JNICALL -NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, - int *len, jboolean v4MappedAddress) { - jint family; - family = getInetAddress_family(env, iaObj); - /* needs work. 1. family 2. clean up him6 etc deallocate memory */ - if (ipv6_available() && !(family == java_net_InetAddress_IPv4 && - v4MappedAddress == JNI_FALSE)) { - struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; +NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, + SOCKETADDRESS *sa, int *len, + jboolean v4MappedAddress) +{ + jint family = getInetAddress_family(env, iaObj); + memset((char *)sa, 0, sizeof(SOCKETADDRESS)); + + if (ipv6_available() && + !(family == java_net_InetAddress_IPv4 && + v4MappedAddress == JNI_FALSE)) + { jbyte caddr[16]; jint address; if (family == java_net_InetAddress_IPv4) { // convert to IPv4-mapped address - memset((char *) caddr, 0, 16); + memset((char *)caddr, 0, 16); address = getInetAddress_addr(env, iaObj); if (address == INADDR_ANY) { /* we would always prefer IPv6 wildcard address - caddr[10] = 0xff; - caddr[11] = 0xff; */ + * caddr[10] = 0xff; + * caddr[11] = 0xff; */ } else { caddr[10] = 0xff; caddr[11] = 0xff; @@ -810,22 +789,19 @@ } else { getInet6Address_ipaddress(env, iaObj, (char *)caddr); } - memset((char *)him6, 0, sizeof(struct sockaddr_in6)); - 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); + sa->sa6.sin6_port = htons(port); + memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr)); + sa->sa6.sin6_family = AF_INET6; + if (len != NULL) { + *len = sizeof(struct sockaddr_in6); + } -#if defined(_ALLBSD_SOURCE) -// XXXBSD: should we do something with scope id here ? see below linux comment -/* MMM: Come back to this! */ -#endif - +#ifdef __linux__ /* * On Linux if we are connecting to a link-local address * we need to specify the interface in the scope_id (2.4 kernel only) * - * If the scope was cached the we use the cached value. If not cached but + * If the scope was cached then we use the cached value. If not cached but * specified in the Inet6Address we use that, but we first check if the * address needs to be routed via the loopback interface. In this case, * we override the specified value with that of the loopback interface. @@ -833,9 +809,8 @@ * we try to determine a value from the routing table. In all these * cases the used value is cached for further use. */ -#ifdef __linux__ - if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))) { - int cached_scope_id = 0, scope_id = 0; + if (IN6_IS_ADDR_LINKLOCAL(&sa->sa6.sin6_addr)) { + unsigned int cached_scope_id = 0, scope_id = 0; if (ia6_cachedscopeidID) { cached_scope_id = (int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID); @@ -850,7 +825,7 @@ /* check user-specified value for loopback case * that needs to be overridden */ - if (kernelIsV24() && needsLoopbackRoute (&him6->sin6_addr)) { + if (kernelIsV24() && needsLoopbackRoute(&sa->sa6.sin6_addr)) { cached_scope_id = lo_scope_id; (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); } @@ -860,11 +835,11 @@ * try determine the appropriate interface. */ if (kernelIsV24()) { - cached_scope_id = getDefaultIPv6Interface(&(him6->sin6_addr)); + cached_scope_id = getDefaultIPv6Interface(&sa->sa6.sin6_addr); } else { - cached_scope_id = getLocalScopeID((char *)&(him6->sin6_addr)); + cached_scope_id = getLocalScopeID((char *)&(sa->sa6.sin6_addr)); if (cached_scope_id == 0) { - cached_scope_id = getDefaultIPv6Interface(&(him6->sin6_addr)); + cached_scope_id = getDefaultIPv6Interface(&sa->sa6.sin6_addr); } } (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); @@ -876,53 +851,37 @@ * If we have a scope_id use the extended form * of sockaddr_in6. */ - - struct sockaddr_in6 *him6 = - (struct sockaddr_in6 *)him; - him6->sin6_scope_id = cached_scope_id != 0 ? - cached_scope_id : scope_id; - *len = sizeof(struct sockaddr_in6); + sa->sa6.sin6_scope_id = cached_scope_id == 0 ? scope_id : cached_scope_id; } #else - /* handle scope_id for solaris */ - + /* handle scope_id */ if (family != java_net_InetAddress_IPv4) { if (ia6_scopeidID) { - him6->sin6_scope_id = getInet6Address_scopeid(env, iaObj); + sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj); } } #endif } else { - struct sockaddr_in *him4 = (struct sockaddr_in *)him; jint address; - if (family == java_net_InetAddress_IPv6) { + if (family != java_net_InetAddress_IPv4) { 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); + sa->sa4.sin_port = htons(port); + sa->sa4.sin_addr.s_addr = htonl(address); + sa->sa4.sin_family = AF_INET; + if (len != NULL) { + *len = sizeof(struct sockaddr_in); + } } return 0; } void -NET_SetTrafficClass(struct sockaddr *him, int trafficClass) { - if (him->sa_family == AF_INET6) { - struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; - him6->sin6_flowinfo = htonl((trafficClass & 0xff) << 20); - } -} - -JNIEXPORT jint JNICALL -NET_GetPortFromSockaddr(struct sockaddr *him) { - if (him->sa_family == AF_INET6) { - return ntohs(((struct sockaddr_in6*)him)->sin6_port); - } else { - return ntohs(((struct sockaddr_in*)him)->sin_port); +NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) { + if (sa->sa.sa_family == AF_INET6) { + sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20); } } @@ -1488,7 +1447,7 @@ * */ int -NET_Bind(int fd, struct sockaddr *him, int len) +NET_Bind(int fd, SOCKETADDRESS *sa, int len) { #if defined(__solaris__) int level = -1; @@ -1503,9 +1462,8 @@ * ## When IPv6 is enabled this will be an IPv4-mapped * ## with family set to AF_INET6 */ - if (him->sa_family == AF_INET) { - struct sockaddr_in *sa = (struct sockaddr_in *)him; - if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) { + if (sa->sa.sa_family == AF_INET) { + if ((ntohl(sa->sa4.sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) { errno = EADDRNOTAVAIL; return -1; } @@ -1524,8 +1482,9 @@ */ alen = sizeof(arg); - if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (char *)&arg, &alen) == 0) { + if (useExclBind || + getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg, &alen) == 0) + { if (useExclBind || arg == 0) { /* * SO_REUSEADDR is disabled or sun.net.useExclusiveBind @@ -1533,8 +1492,8 @@ * UDP_EXCLBIND */ alen = sizeof(arg); - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg, - &alen) == 0) { + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg, &alen) == 0) + { if (arg == SOCK_STREAM) { level = IPPROTO_TCP; exclbind = TCP_EXCLBIND; @@ -1545,14 +1504,13 @@ } arg = 1; - setsockopt(fd, level, exclbind, (char *)&arg, - sizeof(arg)); + setsockopt(fd, level, exclbind, (char *)&arg, sizeof(arg)); } } #endif - rv = bind(fd, him, len); + rv = bind(fd, &sa->sa, len); #if defined(__solaris__) if (rv < 0) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnet/net_util_md.h --- a/jdk/src/java.base/unix/native/libnet/net_util_md.h Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h Wed Jul 05 22:42:01 2017 +0200 @@ -30,32 +30,6 @@ #include #include -int NET_Timeout(int s, long timeout); -int NET_Timeout0(int s, long timeout, long currentTime); -int NET_Read(int s, void* buf, size_t len); -int NET_NonBlockingRead(int s, void* buf, size_t len); -int NET_TimeoutWithCurrentTime(int s, long timeout, long currentTime); -long NET_GetCurrentTime(); -int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, socklen_t *fromlen); -int NET_ReadV(int s, const struct iovec * vector, int count); -int NET_Send(int s, void *msg, int len, unsigned int flags); -int NET_SendTo(int s, const void *msg, int len, unsigned int - flags, const struct sockaddr *to, int tolen); -int NET_Writev(int s, const struct iovec * vector, int count); -int NET_Connect(int s, struct sockaddr *addr, int addrlen); -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); -int NET_SocketClose(int s); -int NET_Dup2(int oldfd, int newfd); -int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); -int NET_SocketAvailable(int s, jint *pbytes); - -void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, - const char* hostname, - int gai_error); -void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, - const char *defaultDetail); - /************************************************************************ * Macros and constants */ @@ -91,9 +65,36 @@ } SOCKETADDRESS; /************************************************************************ - * Utilities + * Functions */ +int NET_Timeout(int s, long timeout); +int NET_Timeout0(int s, long timeout, long currentTime); +int NET_Read(int s, void* buf, size_t len); +int NET_NonBlockingRead(int s, void* buf, size_t len); +int NET_TimeoutWithCurrentTime(int s, long timeout, long currentTime); +long NET_GetCurrentTime(); +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen); +int NET_ReadV(int s, const struct iovec * vector, int count); +int NET_Send(int s, void *msg, int len, unsigned int flags); +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen); +int NET_Writev(int s, const struct iovec * vector, int count); +int NET_Connect(int s, struct sockaddr *addr, int addrlen); +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int NET_SocketClose(int s); +int NET_Dup2(int oldfd, int newfd); +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); +int NET_SocketAvailable(int s, jint *pbytes); + +void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, + const char* hostname, + int gai_error); +void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, + const char *defaultDetail); +void NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass); + #ifdef __linux__ int kernelIsV24(); int getDefaultIPv6Interface(struct in6_addr *target_addr); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c --- a/jdk/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -181,11 +181,11 @@ */ senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); if (senderAddr != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, &sa.sa, senderAddr)) { + if (!NET_SockaddrEqualsInetAddress(env, &sa, senderAddr)) { senderAddr = NULL; } else { jint port = (*env)->GetIntField(env, this, dci_senderPortID); - if (port != NET_GetPortFromSockaddr(&sa.sa)) { + if (port != NET_GetPortFromSockaddr(&sa)) { senderAddr = NULL; } } @@ -193,7 +193,7 @@ if (senderAddr == NULL) { jobject isa = NULL; int port = 0; - jobject ia = NET_SockaddrToInetAddress(env, &sa.sa, &port); + jobject ia = NET_SockaddrToInetAddress(env, &sa, &port); if (ia != NULL) { isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); } @@ -201,7 +201,7 @@ (*env)->SetObjectField(env, this, dci_senderAddrID, ia); (*env)->SetIntField(env, this, dci_senderPortID, - NET_GetPortFromSockaddr(&sa.sa)); + NET_GetPortFromSockaddr(&sa)); (*env)->SetObjectField(env, this, dci_senderID, isa); } return n; @@ -215,14 +215,14 @@ jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); SOCKETADDRESS sa; - int sa_len = sizeof(SOCKETADDRESS); + int sa_len = 0; jint n = 0; if (len > MAX_PACKET_LEN) { len = MAX_PACKET_LEN; } - if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa.sa, + if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa, &sa_len, preferIPv6) != 0) { return IOS_THROWN; } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c --- a/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c Wed Jul 05 22:42:01 2017 +0200 @@ -64,7 +64,7 @@ if (getpeername(fd, &sa.sa, &len) == 0) { if (matchFamily(&sa.sa)) { - remote_ia = NET_SockaddrToInetAddress(env, &sa.sa, (int *)&remote_port); + remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); } } @@ -81,7 +81,7 @@ if (getpeername(fd, &sa.sa, &len) == 0) { if (matchFamily(&sa.sa)) { - NET_SockaddrToInetAddress(env, &sa.sa, (int *)&remote_port); + NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); } } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnio/ch/Net.c --- a/jdk/src/java.base/unix/native/libnio/ch/Net.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c Wed Jul 05 22:42:01 2017 +0200 @@ -274,15 +274,15 @@ jboolean useExclBind, jobject iao, int port) { SOCKETADDRESS sa; - int sa_len = sizeof(SOCKETADDRESS); + int sa_len = 0; int rv = 0; - if (NET_InetAddressToSockaddr(env, iao, port, &sa.sa, &sa_len, + if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { return; } - rv = NET_Bind(fdval(env, fdo), &sa.sa, sa_len); + rv = NET_Bind(fdval(env, fdo), &sa, sa_len); if (rv != 0) { handleSocketError(env, errno); } @@ -300,10 +300,10 @@ jobject fdo, jobject iao, jint port) { SOCKETADDRESS sa; - int sa_len = sizeof(SOCKETADDRESS); + int sa_len = 0; int rv; - if (NET_InetAddressToSockaddr(env, iao, port, &sa.sa, &sa_len, + if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { return IOS_THROWN; } @@ -349,7 +349,7 @@ return -1; #endif /* _ALLBSD_SOURCE */ } - return NET_GetPortFromSockaddr(&sa.sa); + return NET_GetPortFromSockaddr(&sa); } JNIEXPORT jobject JNICALL @@ -382,7 +382,7 @@ return NULL; #endif /* _ALLBSD_SOURCE */ } - return NET_SockaddrToInetAddress(env, &sa.sa, &port); + return NET_SockaddrToInetAddress(env, &sa, &port); } JNIEXPORT jint JNICALL diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c --- a/jdk/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -112,7 +112,7 @@ } (*env)->SetIntField(env, newfdo, fd_fdID, newfd); - remote_ia = NET_SockaddrToInetAddress(env, &sa.sa, (int *)&remote_port); + remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); CHECK_NULL_RETURN(remote_ia, IOS_THROWN); isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); CHECK_NULL_RETURN(isa, IOS_THROWN); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java --- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -233,11 +233,14 @@ int childStart = 0; int parentEnd = pn; + boolean isDirectoryRelative = + pn == 2 && isLetter(parent.charAt(0)) && parent.charAt(1) == ':'; + if ((cn > 1) && (c.charAt(0) == slash)) { if (c.charAt(1) == slash) { /* Drop prefix when child is a UNC pathname */ childStart = 2; - } else { + } else if (!isDirectoryRelative) { /* Drop prefix when child is drive-relative */ childStart = 1; @@ -254,7 +257,7 @@ int strlen = parentEnd + cn - childStart; char[] theChars = null; - if (child.charAt(childStart) == slash) { + if (child.charAt(childStart) == slash || isDirectoryRelative) { theChars = new char[strlen]; parent.getChars(0, parentEnd, theChars, 0); child.getChars(childStart, cn, theChars, parentEnd); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -53,7 +53,7 @@ break; } if (recvfrom(fd, buf, 1, MSG_PEEK, - (struct sockaddr *)&rmtaddr, &addrlen) != SOCKET_ERROR) { + &rmtaddr.sa, &addrlen) != SOCKET_ERROR) { break; } if (WSAGetLastError() != WSAECONNRESET) { @@ -61,7 +61,7 @@ break; } - recvfrom(fd, buf, 1, 0, (struct sockaddr *)&rmtaddr, &addrlen); + recvfrom(fd, buf, 1, 0, &rmtaddr.sa, &addrlen); got_icmp = JNI_TRUE; } @@ -134,14 +134,13 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, jboolean exclBind) { SOCKETADDRESS sa; - int rv; - int sa_len = sizeof(sa); + int rv, sa_len = 0; - if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &sa_len, JNI_TRUE) != 0) { return; } - rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind); + rv = NET_WinBind(fd, &sa, sa_len, exclBind); if (rv == SOCKET_ERROR) { if (WSAGetLastError() == WSAEACCES) { @@ -159,17 +158,15 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConnect (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { SOCKETADDRESS sa; - int rv; - int sa_len = sizeof(sa); + int rv, sa_len = 0, t = TRUE; DWORD x1, x2; /* ignored result codes */ - int t = TRUE; - if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &sa_len, JNI_TRUE) != 0) { return; } - rv = connect(fd, (struct sockaddr *)&sa, sa_len); + rv = connect(fd, &sa.sa, sa_len); if (rv == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "connect"); return; @@ -192,7 +189,7 @@ int t = FALSE; memset(&sa, 0, sa_len); - connect(fd, (struct sockaddr *)&sa, sa_len); + connect(fd, &sa.sa, sa_len); /* see comment in socketCreate */ WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0); @@ -219,7 +216,7 @@ SOCKETADDRESS sa; int len = sizeof(sa); - if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) { + if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "getsockname"); return -1; } @@ -238,12 +235,12 @@ jobject iaObj; int port; - if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) { + if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); return NULL; } - iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &sa, &port); return iaObj; } @@ -316,7 +313,7 @@ /* receive the packet */ rv = recvfrom(fd, fullPacket, packetBufferLen, flags, - (struct sockaddr *)&sa, &sa_len); + &sa.sa, &sa_len); if (rv == SOCKET_ERROR && (WSAGetLastError() == WSAECONNRESET)) { /* An icmp port unreachable - we must receive this as Windows @@ -383,15 +380,13 @@ */ packetAddress = (*env)->GetObjectField(env, dpObj, dp_addressID); if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa, - packetAddress)) { + if (!NET_SockaddrEqualsInetAddress(env, &sa, packetAddress)) { /* force a new InetAddress to be created */ packetAddress = NULL; } } if (packetAddress == NULL) { - packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, - &port); + packetAddress = NET_SockaddrToInetAddress(env, &sa, &port); if (packetAddress != NULL) { /* stuff the new Inetaddress into the packet */ (*env)->SetObjectField(env, dpObj, dp_addressID, packetAddress); @@ -422,20 +417,18 @@ (JNIEnv *env, jclass clazz, jint fd, jbyteArray data, jint offset, jint length, jobject iaObj, jint port, jboolean connected) { SOCKETADDRESS sa; - int sa_len = sizeof(sa); - SOCKETADDRESS *sap = &sa; + int rv, sa_len = 0; + struct sockaddr *sap = 0; char BUF[MAX_BUFFER_LEN]; char *fullPacket; - int rv; - if (connected) { - sap = 0; /* arg to sendto () null in this case */ - sa_len = 0; - } else { - if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, - &sa_len, JNI_TRUE) != 0) { + // if already connected, sap arg to sendto() is null + if (!connected) { + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, + &sa_len, JNI_TRUE) != 0) { return; } + sap = &sa.sa; } if (length > MAX_BUFFER_LEN) { @@ -456,7 +449,7 @@ (*env)->GetByteArrayRegion(env, data, offset, length, (jbyte *)fullPacket); - rv = sendto(fd, fullPacket, length, 0, (struct sockaddr *)sap, sa_len); + rv = sendto(fd, fullPacket, length, 0, sap, sa_len); if (rv == SOCKET_ERROR) { if (rv == -1) { NET_ThrowNew(env, WSAGetLastError(), "Datagram send failed"); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -89,15 +89,14 @@ jboolean exclBind) { SOCKETADDRESS sa; - int rv; - int sa_len = sizeof(sa); + int rv, sa_len = 0; - if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, - &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, + &sa_len, JNI_TRUE) != 0) { return; } - rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind); + rv = NET_WinBind(fd, &sa, sa_len, exclBind); if (rv == SOCKET_ERROR) NET_ThrowNew(env, WSAGetLastError(), "NET_Bind"); @@ -111,15 +110,14 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { SOCKETADDRESS sa; - int rv; - int sa_len = sizeof(sa); + int rv, sa_len = 0; - if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa, - &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, + &sa_len, JNI_TRUE) != 0) { return -1; } - rv = connect(fd, (struct sockaddr *)&sa, sa_len); + rv = connect(fd, &sa.sa, sa_len); if (rv == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK) { @@ -217,7 +215,7 @@ SOCKETADDRESS sa; int len = sizeof(sa); - if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) { + if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { if (WSAGetLastError() == WSAENOTSOCK) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); @@ -243,11 +241,11 @@ jclass iaContainerClass; jfieldID iaFieldID; - if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) { + if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name"); return; } - iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &sa, &port); CHECK_NULL(iaObj); iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj); @@ -283,7 +281,7 @@ int len = sizeof(sa); memset((char *)&sa, 0, len); - newfd = accept(fd, (struct sockaddr *)&sa, &len); + newfd = accept(fd, &sa.sa, &len); if (newfd == INVALID_SOCKET) { if (WSAGetLastError() == -2) { @@ -298,7 +296,7 @@ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); - ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); + ia = NET_SockaddrToInetAddress(env, &sa, &port); isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); (*env)->SetObjectArrayElement(env, isaa, 0, isa); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -420,18 +420,13 @@ jboolean exclBind) { jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); - - int fd, fd1 = -1, family; int ipv6_supported = ipv6_available(); - + int fd, fd1 = -1, lcladdrlen = 0; SOCKETADDRESS lcladdr; - int lcladdrlen = sizeof(SOCKETADDRESS); - int address; - memset((char *)&lcladdr, 0, sizeof(lcladdr)); - - family = getInetAddress_family(env, addressObj); - if (family == java_net_InetAddress_IPv6 && !ipv6_supported) { + if (getInetAddress_family(env, addressObj) == java_net_InetAddress_IPv6 && + !ipv6_supported) + { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); return; @@ -446,14 +441,13 @@ fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); } } + if (IS_NULL(addressObj)) { JNU_ThrowNullPointerException(env, "argument address"); return; - } else { - address = getInetAddress_addr(env, addressObj); } - if (NET_InetAddressToSockaddr(env, addressObj, port, &lcladdr.sa, + if (NET_InetAddressToSockaddr(env, addressObj, port, &lcladdr, &lcladdrlen, JNI_FALSE) != 0) { return; } @@ -493,7 +487,7 @@ return; } } else { - if (NET_WinBind(fd, &lcladdr.sa, lcladdrlen, exclBind) == -1) { + if (NET_WinBind(fd, &lcladdr, lcladdrlen, exclBind) == -1) { if (WSAGetLastError() == WSAEACCES) { WSASetLastError(WSAEADDRINUSE); } @@ -507,7 +501,7 @@ NET_ThrowCurrent(env, "getsockname"); return; } - port = ntohs((u_short) GET_PORT (&lcladdr)); + port = ntohs((u_short)GET_PORT(&lcladdr)); } (*env)->SetIntField(env, this, pdsi_localPortID, port); } @@ -520,27 +514,25 @@ */ JNIEXPORT void JNICALL -Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this, - jobject address, jint port) { - /* The object's field */ +Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0 + (JNIEnv *env, jobject this, jobject address, jint port) +{ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); - /* The fdObj'fd */ - jint fd=-1, fd1=-1, fdc; - /* The packetAddress address, family and port */ - jint addr, family; + jint fd = -1, fd1 = -1, fdc, family; SOCKETADDRESS rmtaddr; - int rmtaddrlen; - int ipv6_supported = ipv6_available(); + int rmtaddrlen = 0; if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); return; } + if (!IS_NULL(fdObj)) { fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); } + if (!IS_NULL(fd1Obj)) { fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID); } @@ -550,10 +542,8 @@ return; } - addr = getInetAddress_addr(env, address); - family = getInetAddress_family(env, address); - if (family == java_net_InetAddress_IPv6 && !ipv6_supported) { + if (family == java_net_InetAddress_IPv6 && !ipv6_available()) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); return; @@ -572,12 +562,12 @@ res = WSAIoctl(fdc,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0); } - if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr.sa, + if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr, &rmtaddrlen, JNI_FALSE) != 0) { return; } - if (connect(fdc, &rmtaddr.sa, sizeof(rmtaddr)) == -1) { + if (connect(fdc, &rmtaddr.sa, rmtaddrlen) == -1) { NET_ThrowCurrent(env, "connect"); return; } @@ -631,9 +621,9 @@ * Signature: (Ljava/net/DatagramPacket;)V */ JNIEXPORT void JNICALL -Java_java_net_TwoStacksPlainDatagramSocketImpl_send(JNIEnv *env, jobject this, - jobject packet) { - +Java_java_net_TwoStacksPlainDatagramSocketImpl_send + (JNIEnv *env, jobject this, jobject packet) +{ char BUF[MAX_BUFFER_LEN]; char *fullPacket; jobject fdObj; @@ -647,11 +637,10 @@ jbyteArray packetBuffer; jboolean connected; - SOCKETADDRESS rmtaddr, *addrp = &rmtaddr; + SOCKETADDRESS rmtaddr; + struct sockaddr *addrp = 0; int addrlen = 0; - memset((char *)&rmtaddr, 0, sizeof(rmtaddr)); - if (IS_NULL(packet)) { JNU_ThrowNullPointerException(env, "null packet"); return; @@ -696,14 +685,13 @@ packetBufferLen = MAX_PACKET_LEN; } - if (connected) { - addrp = 0; /* arg to sendto () null in this case */ - addrlen = 0; - } else { - if (NET_InetAddressToSockaddr(env, iaObj, packetPort, &rmtaddr.sa, + // sockaddr arg to sendto() is null if already connected + if (!connected) { + if (NET_InetAddressToSockaddr(env, iaObj, packetPort, &rmtaddr, &addrlen, JNI_FALSE) != 0) { return; } + addrp = &rmtaddr.sa; } if (packetBufferLen > MAX_BUFFER_LEN) { @@ -753,11 +741,12 @@ fullPacket = &(BUF[0]); } - (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen, - (jbyte *)fullPacket); - if (sendto(fd, fullPacket, packetBufferLen, 0, - (struct sockaddr *)addrp, addrlen) == SOCKET_ERROR) { - NET_ThrowCurrent(env, "Datagram send failed"); + (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, + packetBufferLen, (jbyte *)fullPacket); + if (sendto(fd, fullPacket, packetBufferLen, 0, addrp, + addrlen) == SOCKET_ERROR) + { + NET_ThrowCurrent(env, "Datagram send failed"); } if (packetBufferLen > MAX_BUFFER_LEN) { @@ -1147,14 +1136,14 @@ */ packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, &remote_addr.sa, + if (!NET_SockaddrEqualsInetAddress(env, &remote_addr, packetAddress)) { /* force a new InetAddress to be created */ packetAddress = NULL; } } if (packetAddress == NULL) { - packetAddress = NET_SockaddrToInetAddress(env, &remote_addr.sa, + packetAddress = NET_SockaddrToInetAddress(env, &remote_addr, &port); /* stuff the new Inetaddress in the packet */ (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); @@ -1431,20 +1420,21 @@ * can't update any existing InetAddress because it is immutable */ packetAddress = (*env)->GetObjectField(env, packet, dp_addressID); - if (packetAddress != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, &remote_addr.sa, packetAddress)) { + if (!NET_SockaddrEqualsInetAddress(env, &remote_addr, + packetAddress)) { /* force a new InetAddress to be created */ packetAddress = NULL; } } if (packetAddress == NULL) { - packetAddress = NET_SockaddrToInetAddress(env, &remote_addr.sa, &port); + packetAddress = NET_SockaddrToInetAddress(env, &remote_addr, + &port); /* stuff the new Inetaddress in the packet */ (*env)->SetObjectField(env, packet, dp_addressID, packetAddress); } else { /* only get the new port number */ - port = NET_GetPortFromSockaddr(&remote_addr.sa); + port = NET_GetPortFromSockaddr(&remote_addr); } /* populate the packet */ (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n, @@ -1528,7 +1518,7 @@ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); int ipv6_supported = ipv6_available(); - int fd=-1, fd1=-1; + int fd = -1, fd1 = -1; if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) { return; @@ -1799,7 +1789,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption (JNIEnv *env,jobject this, jint opt,jobject value) { - int fd=-1, fd1=-1; + int fd = -1, fd1 = -1; int levelv4 = 0, levelv6 = 0, optnamev4 = 0, optnamev6 = 0, optlen = 0; union { int i; @@ -2167,7 +2157,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption (JNIEnv *env, jobject this, jint opt) { - int fd=-1, fd1=-1; + int fd = -1, fd1 = -1; int level, optname, optlen; union { int i; @@ -2255,7 +2245,7 @@ (JNIEnv *env, jobject this, jint family) { int fd = -1, fd1 = -1; - SOCKETADDRESS him; + SOCKETADDRESS sa; int len = 0; int port; jobject iaObj; @@ -2288,12 +2278,12 @@ return NULL; } - if (getsockname(fd, &him.sa, &len) == -1) { + if (getsockname(fd, &sa.sa, &len) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); return NULL; } - iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &sa, &port); return iaObj; } @@ -2430,7 +2420,7 @@ int len, family; int ipv6_supported = ipv6_available(); - int cmd ; + int cmd; memset((char *)&in, 0, sizeof(in)); memset((char *)&name, 0, sizeof(name)); @@ -2452,7 +2442,7 @@ return; } - if (NET_InetAddressToSockaddr(env, iaObj, 0, &name.sa, &len, JNI_FALSE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, 0, &name, &len, JNI_FALSE) != 0) { return; } @@ -2473,7 +2463,7 @@ return; } if (IS_NULL(niObj)) { - len = sizeof (in); + len = sizeof(in); if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&in, &len) < 0) { NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed"); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -175,8 +175,8 @@ */ JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this, - jobject iaObj, jint port, - jint timeout) + jobject iaObj, jint port, + jint timeout) { jint localport = (*env)->GetIntField(env, this, psi_localportID); @@ -193,11 +193,11 @@ jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); - SOCKETADDRESS him; + SOCKETADDRESS sa; /* The result of the connection */ int connect_res; - memset((char *)&him, 0, sizeof(him)); + memset((char *)&sa, 0, sizeof(sa)); if (!IS_NULL(fdObj)) { fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); @@ -212,11 +212,12 @@ return; } - if (NET_InetAddressToSockaddr(env, iaObj, port, &him.sa, &len, JNI_FALSE) != 0) { - return; + if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len, + JNI_FALSE) != 0) { + return; } - family = him.sa.sa_family; + family = sa.sa.sa_family; if (family == AF_INET6) { if (!ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -248,7 +249,7 @@ (*env)->SetObjectField(env, this, psi_fd1ID, NULL); if (timeout <= 0) { - connect_res = connect(fd, &him.sa, sizeof(SOCKETADDRESS)); + connect_res = connect(fd, &sa.sa, sizeof(SOCKETADDRESS)); if (connect_res == SOCKET_ERROR) { connect_res = WSAGetLastError(); } @@ -261,7 +262,7 @@ ioctlsocket(fd, FIONBIO, &optval); /* initiate the connect */ - connect_res = connect(fd, &him.sa, sizeof(SOCKETADDRESS)); + connect_res = connect(fd, &sa.sa, sizeof(SOCKETADDRESS)); if (connect_res == SOCKET_ERROR) { if (WSAGetLastError() != WSAEWOULDBLOCK) { connect_res = WSAGetLastError(); @@ -362,7 +363,7 @@ */ u_short port; int len = sizeof(SOCKETADDRESS); - if (getsockname(fd, &him.sa, &len) == -1) { + if (getsockname(fd, &sa.sa, &len) == -1) { if (WSAGetLastError() == WSAENOTSOCK) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); @@ -371,7 +372,7 @@ } return; } - port = ntohs((u_short)GET_PORT(&him)); + port = ntohs((u_short)GET_PORT(&sa)); (*env)->SetIntField(env, this, psi_localportID, (int) port); } } @@ -396,7 +397,7 @@ int family; int rv; - SOCKETADDRESS him; + SOCKETADDRESS sa; fdObj = (*env)->GetObjectField(env, this, psi_fdID); fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID); @@ -424,13 +425,13 @@ return; } - if (NET_InetAddressToSockaddr(env, iaObj, localport, &him.sa, &len, + if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len, JNI_FALSE) != 0) { return; } if (ipv6_supported) { struct ipv6bind v6bind; - v6bind.addr = &him; + v6bind.addr = &sa.sa; v6bind.ipv4_fd = fd; v6bind.ipv6_fd = fd1; rv = NET_BindV6(&v6bind, exclBind); @@ -462,7 +463,7 @@ (*env)->SetObjectField(env, this, psi_fd1ID, NULL); } } else { - rv = NET_WinBind(fd, &him.sa, len, exclBind); + rv = NET_WinBind(fd, &sa, len, exclBind); } if (rv == -1) { @@ -481,11 +482,11 @@ int len = sizeof(SOCKETADDRESS); u_short port; - if (getsockname(him.sa.sa_family == AF_INET ? fd: fd1, &him.sa, &len) == -1) { + if (getsockname(sa.sa.sa_family == AF_INET ? fd : fd1, &sa.sa, &len) == -1) { NET_ThrowCurrent(env, "getsockname in plain socketBind"); return; } - port = ntohs((u_short) GET_PORT (&him)); + port = ntohs((u_short) GET_PORT (&sa)); (*env)->SetIntField(env, this, psi_localportID, (int)port); } else { @@ -529,7 +530,7 @@ JNU_ThrowNullPointerException(env, "socket address"); return; } - if (NET_InetAddressToSockaddr(env, address, 0, &addr.sa, &addrlen, + if (NET_InetAddressToSockaddr(env, address, 0, &addr, &addrlen, JNI_FALSE) != 0) { return; } @@ -585,7 +586,7 @@ /* the fd int field on fdObj */ jint fd=-1, fd1=-1; - SOCKETADDRESS him; + SOCKETADDRESS sa; jint len; if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { @@ -676,7 +677,7 @@ } } } - fd = accept(fd, &him.sa, &len); + fd = accept(fd, &sa.sa, &len); if (fd < 0) { /* REMIND: SOCKET CLOSED PROBLEM */ if (fd == -2) { @@ -691,7 +692,7 @@ SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0); (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd); - if (him.sa.sa_family == AF_INET) { + if (sa.sa.sa_family == AF_INET) { if (inet4Cls == NULL) { jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); if (c != NULL) { @@ -717,7 +718,7 @@ return; } - setInetAddress_addr(env, socketAddressObj, ntohl(him.sa4.sin_addr.s_addr)); + setInetAddress_addr(env, socketAddressObj, ntohl(sa.sa4.sin_addr.s_addr)); setInetAddress_family(env, socketAddressObj, java_net_InetAddress_IPv4); (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); } else { @@ -743,14 +744,14 @@ NET_SocketClose(fd); return; } - setInet6Address_ipaddress(env, socketAddressObj, (char *)&him.sa6.sin6_addr); + setInet6Address_ipaddress(env, socketAddressObj, (char *)&sa.sa6.sin6_addr); setInetAddress_family(env, socketAddressObj, java_net_InetAddress_IPv6); - setInet6Address_scopeid(env, socketAddressObj, him.sa6.sin6_scope_id); + setInet6Address_scopeid(env, socketAddressObj, sa.sa6.sin6_scope_id); } /* fields common to AF_INET and AF_INET6 */ - port = ntohs ((u_short) GET_PORT (&him)); + port = ntohs ((u_short)GET_PORT(&sa)); (*env)->SetIntField(env, socket, psi_portID, (int)port); port = (*env)->GetIntField(env, this, psi_localportID); (*env)->SetIntField(env, socket, psi_localportID, port); @@ -1025,14 +1026,14 @@ * SO_BINDADDR isn't a socket option */ if (opt == java_net_SocketOptions_SO_BINDADDR) { - SOCKETADDRESS him; + SOCKETADDRESS sa; int len = sizeof(SOCKETADDRESS); int port; jobject iaObj; jclass iaCntrClass; jfieldID iaFieldID; - memset((char *)&him, 0, len); + memset((char *)&sa, 0, len); if (fd == -1) { /* must be an IPV6 only socket. Case where both sockets are != -1 @@ -1041,12 +1042,12 @@ fd = getFD1 (env, this); } - if (getsockname(fd, &him.sa, &len) < 0) { + if (getsockname(fd, &sa.sa, &len) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); return -1; } - iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port); + iaObj = NET_SockaddrToInetAddress(env, &sa, &port); CHECK_NULL_RETURN(iaObj, -1); iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnet/net_util_md.c --- a/jdk/src/java.base/windows/native/libnet/net_util_md.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c Wed Jul 05 22:42:01 2017 +0200 @@ -488,10 +488,10 @@ * Should be only called by the wrapper method NET_WinBind */ JNIEXPORT int JNICALL -NET_Bind(int s, struct sockaddr *him, int len) +NET_Bind(int s, SOCKETADDRESS *sa, int len) { int rv = 0; - rv = bind(s, him, len); + rv = bind(s, &sa->sa, len); if (rv == SOCKET_ERROR) { /* @@ -511,11 +511,11 @@ * if required, and then calls NET_BIND */ JNIEXPORT int JNICALL -NET_WinBind(int s, struct sockaddr *him, int len, jboolean exclBind) +NET_WinBind(int s, SOCKETADDRESS *sa, int len, jboolean exclBind) { if (exclBind == JNI_TRUE) setExclusiveBind(s); - return NET_Bind(s, him, len); + return NET_Bind(s, sa, len); } JNIEXPORT int JNICALL @@ -677,8 +677,8 @@ if (family == AF_INET && (b->addr->sa4.sin_addr.s_addr != INADDR_ANY)) { /* bind to v4 only */ int ret; - ret = NET_WinBind((int)b->ipv4_fd, (struct sockaddr *)b->addr, - sizeof(SOCKETADDRESS), exclBind); + ret = NET_WinBind((int)b->ipv4_fd, b->addr, + sizeof(SOCKETADDRESS), exclBind); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } @@ -689,7 +689,7 @@ if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->sa6.sin6_addr))) { /* bind to v6 only */ int ret; - ret = NET_WinBind((int)b->ipv6_fd, (struct sockaddr *)b->addr, + ret = NET_WinBind((int)b->ipv6_fd, b->addr, sizeof(SOCKETADDRESS), exclBind); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; @@ -719,7 +719,7 @@ oaddr.sa4.sin_addr.s_addr = INADDR_ANY; } - rv = NET_WinBind(fd, (struct sockaddr *)b->addr, sizeof(SOCKETADDRESS), exclBind); + rv = NET_WinBind(fd, b->addr, sizeof(SOCKETADDRESS), exclBind); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } @@ -731,7 +731,7 @@ } bound_port = GET_PORT (b->addr); SET_PORT (&oaddr, bound_port); - if ((rv = NET_WinBind(ofd, &oaddr.sa, + if ((rv = NET_WinBind(ofd, &oaddr, sizeof(SOCKETADDRESS), exclBind)) == SOCKET_ERROR) { int retries; int sotype, arglen=sizeof(sotype); @@ -768,7 +768,7 @@ /* bind random port on first socket */ SET_PORT (&oaddr, 0); - rv = NET_WinBind(ofd, &oaddr.sa, sizeof(SOCKETADDRESS), exclBind); + rv = NET_WinBind(ofd, &oaddr, sizeof(SOCKETADDRESS), exclBind); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } @@ -784,8 +784,7 @@ } bound_port = GET_PORT (&oaddr); SET_PORT (b->addr, bound_port); - rv = NET_WinBind(fd, (struct sockaddr *)b->addr, - sizeof(SOCKETADDRESS), exclBind); + rv = NET_WinBind(fd, b->addr, sizeof(SOCKETADDRESS), exclBind); if (rv != SOCKET_ERROR) { if (family == AF_INET) { @@ -853,31 +852,33 @@ return result == SOCKET_ERROR ? WSAGetLastError() : 0; } -/* If address types is IPv6, then IPv6 must be available. Otherwise - * no address can be generated. In the case of an IPv4 Inetaddress this - * method will return an IPv4 mapped address where IPv6 is available and - * v4MappedAddress is TRUE. Otherwise it will return a sockaddr_in - * structure for an IPv4 InetAddress. -*/ +/** + * See net_util.h for documentation + */ JNIEXPORT int JNICALL -NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, - int *len, jboolean v4MappedAddress) { - jint family, iafam; - iafam = getInetAddress_family(env, iaObj); - 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; +NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, + SOCKETADDRESS *sa, int *len, + jboolean v4MappedAddress) +{ + jint family = getInetAddress_family(env, iaObj); + memset((char *)sa, 0, sizeof(SOCKETADDRESS)); + + if (ipv6_available() && + !(family == java_net_InetAddress_IPv4 && + v4MappedAddress == JNI_FALSE)) + { jbyte caddr[16]; - jint address, scopeid = 0; - jint cached_scope_id = 0; + jint address; + unsigned int scopeid = 0, cached_scope_id = 0; - if (family == AF_INET) { /* will convert to IPv4-mapped address */ - memset((char *) caddr, 0, 16); + 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) { /* we would always prefer IPv6 wildcard address - caddr[10] = 0xff; - caddr[11] = 0xff; */ + * caddr[10] = 0xff; + * caddr[11] = 0xff; */ } else { caddr[10] = 0xff; caddr[11] = 0xff; @@ -889,46 +890,39 @@ } else { getInet6Address_ipaddress(env, iaObj, (char *)caddr); scopeid = getInet6Address_scopeid(env, iaObj); - cached_scope_id = (jint)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID); + cached_scope_id = (unsigned int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID); } - - 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; - if ((family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL( &(him6->sin6_addr) ) - && (!scopeid && !cached_scope_id)) { - cached_scope_id = getDefaultIPv6Interface(env, him6); + sa->sa6.sin6_port = (u_short)htons((u_short)port); + memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr)); + sa->sa6.sin6_family = AF_INET6; + if ((family == java_net_InetAddress_IPv6) && + IN6_IS_ADDR_LINKLOCAL(&sa->sa6.sin6_addr) && + (!scopeid && !cached_scope_id)) + { + cached_scope_id = getDefaultIPv6Interface(env, &sa->sa6); (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); } - him6->sin6_scope_id = scopeid != 0 ? scopeid : cached_scope_id; - *len = sizeof(struct sockaddr_in6) ; + sa->sa6.sin6_scope_id = scopeid == 0 ? cached_scope_id : scopeid; + if (len != NULL) { + *len = sizeof(struct sockaddr_in6); + } } else { - struct sockaddr_in *him4 = (struct sockaddr_in *)him; jint address; - if (family != AF_INET) { - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable"); - return -1; + if (family != java_net_InetAddress_IPv4) { + 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 = (u_long) htonl(address); - him4->sin_family = AF_INET; - *len = sizeof(struct sockaddr_in); + sa->sa4.sin_port = htons((short)port); + sa->sa4.sin_addr.s_addr = (u_long)htonl(address); + sa->sa4.sin_family = AF_INET; + if (len != NULL) { + *len = sizeof(struct sockaddr_in); + } } return 0; } -JNIEXPORT jint JNICALL -NET_GetPortFromSockaddr(struct sockaddr *him) { - if (him->sa_family == AF_INET6) { - return ntohs(((struct sockaddr_in6 *)him)->sin6_port); - } else { - return ntohs(((struct sockaddr_in *)him)->sin_port); - } -} - int NET_IsIPv4Mapped(jbyte* caddr) { int i; @@ -961,16 +955,6 @@ return 1; } -int getScopeID(struct sockaddr *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; - return him6->sin6_scope_id == scope; -} - /** * Wrapper for select/poll with timeout on a single file descriptor. * diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnet/net_util_md.h --- a/jdk/src/java.base/windows/native/libnet/net_util_md.h Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h Wed Jul 05 22:42:01 2017 +0200 @@ -121,7 +121,7 @@ JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind *b, jboolean exclBind); -JNIEXPORT int JNICALL NET_WinBind(int s, struct sockaddr *him, int len, +JNIEXPORT int JNICALL NET_WinBind(int s, SOCKETADDRESS *sa, int len, jboolean exclBind); /* XP versions of the native routines */ diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c --- a/jdk/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -96,7 +96,7 @@ break; } if (recvfrom(fd, buf, 1, MSG_PEEK, - (struct sockaddr *)&sa, &addrlen) != SOCKET_ERROR) { + &sa.sa, &addrlen) != SOCKET_ERROR) { break; } if (WSAGetLastError() != WSAECONNRESET) { @@ -104,7 +104,7 @@ break; } - recvfrom(fd, buf, 1, 0, (struct sockaddr *)&sa, &addrlen); + recvfrom(fd, buf, 1, 0, &sa.sa, &addrlen); got_icmp = JNI_TRUE; } @@ -122,7 +122,7 @@ memset(&sa, 0, sa_len); - rv = connect((SOCKET)fd, (struct sockaddr *)&sa, sa_len); + rv = connect((SOCKET)fd, &sa.sa, sa_len); if (rv == SOCKET_ERROR) { handleSocketError(env, WSAGetLastError()); } else { @@ -153,7 +153,7 @@ (char *)buf, len, 0, - (struct sockaddr *)&sa, + &sa.sa, &sa_len); if (n == SOCKET_ERROR) { @@ -182,12 +182,11 @@ */ senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); if (senderAddr != NULL) { - if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa, - senderAddr)) { + if (!NET_SockaddrEqualsInetAddress(env, &sa, senderAddr)) { senderAddr = NULL; } else { jint port = (*env)->GetIntField(env, this, dci_senderPortID); - if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) { + if (port != NET_GetPortFromSockaddr(&sa)) { senderAddr = NULL; } } @@ -195,7 +194,7 @@ if (senderAddr == NULL) { jobject isa = NULL; int port; - jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); + jobject ia = NET_SockaddrToInetAddress(env, &sa, &port); if (ia != NULL) { isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); } @@ -204,7 +203,7 @@ // update cachedSenderInetAddress/cachedSenderPort (*env)->SetObjectField(env, this, dci_senderAddrID, ia); (*env)->SetIntField(env, this, dci_senderPortID, - NET_GetPortFromSockaddr((struct sockaddr *)&sa)); + NET_GetPortFromSockaddr(&sa)); (*env)->SetObjectField(env, this, dci_senderID, isa); } return n; @@ -219,21 +218,15 @@ jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); SOCKETADDRESS sa; - int sa_len; + int sa_len = 0; jint rv = 0; - if (NET_InetAddressToSockaddr(env, destAddress, destPort, - (struct sockaddr *)&sa, - &sa_len, preferIPv6) != 0) { + if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa, + &sa_len, preferIPv6) != 0) { return IOS_THROWN; } - rv = sendto((SOCKET)fd, - buf, - len, - 0, - (struct sockaddr *)&sa, - sa_len); + rv = sendto((SOCKET)fd, buf, len, 0, &sa.sa, sa_len); if (rv == SOCKET_ERROR) { int theErr = (jint)WSAGetLastError(); if (theErr == WSAEWOULDBLOCK) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnio/ch/Net.c --- a/jdk/src/java.base/windows/native/libnio/ch/Net.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c Wed Jul 05 22:42:01 2017 +0200 @@ -168,13 +168,13 @@ { SOCKETADDRESS sa; int rv; - int sa_len; + int sa_len = 0; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { - return; + if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { + return; } - rv = NET_WinBind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len, isExclBind); + rv = NET_WinBind(fdval(env, fdo), &sa, sa_len, isExclBind); if (rv == SOCKET_ERROR) NET_ThrowNew(env, WSAGetLastError(), "bind"); } @@ -194,14 +194,14 @@ { SOCKETADDRESS sa; int rv; - int sa_len; + int sa_len = 0; SOCKET s = (SOCKET)fdval(env, fdo); - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { return IOS_THROWN; } - rv = connect(s, (struct sockaddr *)&sa, sa_len); + rv = connect(s, &sa.sa, sa_len); if (rv != 0) { int err = WSAGetLastError(); if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) { @@ -226,7 +226,7 @@ SOCKETADDRESS sa; int sa_len = sizeof(sa); - if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { int error = WSAGetLastError(); if (error == WSAEINVAL) { return 0; @@ -234,7 +234,7 @@ NET_ThrowNew(env, error, "getsockname"); return IOS_THROWN; } - return NET_GetPortFromSockaddr((struct sockaddr *)&sa); + return NET_GetPortFromSockaddr(&sa); } JNIEXPORT jobject JNICALL @@ -244,11 +244,11 @@ int sa_len = sizeof(sa); int port; - if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { NET_ThrowNew(env, WSAGetLastError(), "getsockname"); return NULL; } - return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); + return NET_SockaddrToInetAddress(env, &sa, &port); } JNIEXPORT jint JNICALL @@ -257,7 +257,7 @@ SOCKETADDRESS sa; int sa_len = sizeof(sa); - if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { int error = WSAGetLastError(); if (error == WSAEINVAL) { return 0; @@ -265,7 +265,7 @@ NET_ThrowNew(env, error, "getsockname"); return IOS_THROWN; } - return NET_GetPortFromSockaddr((struct sockaddr *)&sa); + return NET_GetPortFromSockaddr(&sa); } JNIEXPORT jobject JNICALL @@ -275,11 +275,11 @@ int sa_len = sizeof(sa); int port; - if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) { NET_ThrowNew(env, WSAGetLastError(), "getsockname"); return NULL; } - return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); + return NET_SockaddrToInetAddress(env, &sa, &port); } JNIEXPORT jint JNICALL diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c --- a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -95,7 +95,7 @@ int addrlen = sizeof(sa); memset((char *)&sa, 0, sizeof(sa)); - newfd = (jint)accept(ssfd, (struct sockaddr *)&sa, &addrlen); + newfd = (jint)accept(ssfd, &sa.sa, &addrlen); if (newfd == INVALID_SOCKET) { int theErr = (jint)WSAGetLastError(); if (theErr == WSAEWOULDBLOCK) { @@ -107,7 +107,7 @@ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); (*env)->SetIntField(env, newfdo, fd_fdID, newfd); - remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port); + remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); CHECK_NULL_RETURN(remote_ia, IOS_THROWN); isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c --- a/jdk/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -88,26 +88,21 @@ Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_connect0(JNIEnv* env, jclass this, jlong socket, jboolean preferIPv6, jobject iao, jint port, jlong ov) { - SOCKET s = (SOCKET) jlong_to_ptr(socket); - OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov); + SOCKET s = (SOCKET)jlong_to_ptr(socket); + OVERLAPPED *lpOverlapped = (OVERLAPPED *)jlong_to_ptr(ov); SOCKETADDRESS sa; - int sa_len; + int sa_len = 0; BOOL res; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, + preferIPv6) != 0) { return IOS_THROWN; } ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED)); - res = (*ConnectEx_func)(s, - (struct sockaddr *)&sa, - sa_len, - NULL, - 0, - NULL, - lpOverlapped); + res = (*ConnectEx_func)(s, &sa.sa, sa_len, NULL, 0, NULL, lpOverlapped); if (res == 0) { int error = GetLastError(); if (error == ERROR_IO_PENDING) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Wed Jul 05 22:42:01 2017 +0200 @@ -231,6 +231,7 @@ private boolean isFullScreenAnimationOn; private volatile boolean isInFullScreen; + private volatile boolean isIconifyAnimationActive; private Window target; private LWWindowPeer peer; @@ -997,6 +998,9 @@ if (peer != null) { peer.notifyIconify(iconify); } + if (iconify) { + isIconifyAnimationActive = false; + } } private void deliverZoom(final boolean isZoomed) { @@ -1071,6 +1075,17 @@ return true; } + private boolean isIconified() { + boolean isIconified = false; + if (target instanceof Frame) { + int state = ((Frame)target).getExtendedState(); + if ((state & Frame.ICONIFIED) != 0) { + isIconified = true; + } + } + return isIconifyAnimationActive || isIconified; + } + private boolean isOneOfOwnersOrSelf(CPlatformWindow window) { while (window != null) { if (this == window) { @@ -1094,11 +1109,14 @@ // the windows are ordered above their nearest owner; ancestors of the window, // which is going to become 'main window', are placed above their siblings. CPlatformWindow rootOwner = getRootOwner(); - if (rootOwner.isVisible()) { + if (rootOwner.isVisible() && !rootOwner.isIconified()) { CWrapper.NSWindow.orderFront(rootOwner.getNSWindowPtr()); } - final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor(); - orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target)); + // Do not order child windows of iconified owner. + if (!rootOwner.isIconified()) { + final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor(); + orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target)); + } } private void orderAboveSiblingsImpl(Window[] windows) { @@ -1109,10 +1127,12 @@ // Go through the list of windows and perform ordering. for (Window w : windows) { + boolean iconified = false; final Object p = componentAccessor.getPeer(w); if (p instanceof LWWindowPeer) { CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow(); - if (pw != null && pw.isVisible()) { + iconified = isIconified(); + if (pw != null && pw.isVisible() && !iconified) { // If the window is one of ancestors of 'main window' or is going to become main by itself, // the window should be ordered above its siblings; otherwise the window is just ordered // above its nearest parent. @@ -1125,10 +1145,13 @@ pw.applyWindowLevel(w); } } - // Retrieve the child windows for each window from the list and store them for future use. + // Retrieve the child windows for each window from the list except iconified ones + // and store them for future use. // Note: we collect data about child windows even for invisible owners, since they may have // visible children. - childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w))); + if (!iconified) { + childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w))); + } } // If some windows, which have just been ordered, have any child windows, let's start new iteration // and order these child windows. @@ -1149,6 +1172,10 @@ // NATIVE CALLBACKS // ---------------------------------------------------------------------- + private void windowWillMiniaturize() { + isIconifyAnimationActive = true; + } + private void windowDidBecomeMain() { if (checkBlockingAndOrder()) return; // If it's not blocked, make sure it's above its siblings diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Wed Jul 05 22:42:01 2017 +0200 @@ -327,10 +327,43 @@ return [window isKindOfClass: [AWTWindow_Panel class]] || [window isKindOfClass: [AWTWindow_Normal class]]; } +// Retrieves the list of possible window layers (levels) ++ (NSArray*) getWindowLayers { + static NSArray *windowLayers; + static dispatch_once_t token; + + // Initialize the list of possible window layers + dispatch_once(&token, ^{ + // The layers are ordered from front to back, (i.e. the toppest one is the first) + windowLayers = [NSArray arrayWithObjects: + [NSNumber numberWithInt:CGWindowLevelForKey(kCGPopUpMenuWindowLevelKey)], + [NSNumber numberWithInt:CGWindowLevelForKey(kCGFloatingWindowLevelKey)], + [NSNumber numberWithInt:CGWindowLevelForKey(kCGNormalWindowLevelKey)], + nil + ]; + [windowLayers retain]; + }); + return windowLayers; +} + // returns id for the topmost window under mouse + (NSInteger) getTopmostWindowUnderMouseID { NSInteger result = -1; + NSArray *windowLayers = [AWTWindow getWindowLayers]; + // Looking for the window under mouse starting from the toppest layer + for (NSNumber *layer in windowLayers) { + result = [AWTWindow getTopmostWindowUnderMouseIDImpl:[layer integerValue]]; + if (result != -1) { + break; + } + } + return result; +} + ++ (NSInteger) getTopmostWindowUnderMouseIDImpl:(NSInteger)windowLayer { + NSInteger result = -1; + NSRect screenRect = [[NSScreen mainScreen] frame]; NSPoint nsMouseLocation = [NSEvent mouseLocation]; CGPoint cgMouseLocation = CGPointMake(nsMouseLocation.x, screenRect.size.height - nsMouseLocation.y); @@ -339,7 +372,7 @@ for (NSDictionary *window in windows) { NSInteger layer = [[window objectForKey:(id)kCGWindowLayer] integerValue]; - if (layer == 0) { + if (layer == windowLayer) { CGRect rect; CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[window objectForKey:(id)kCGWindowBounds], &rect); if (CGRectContainsPoint(rect, cgMouseLocation)) { @@ -639,6 +672,14 @@ AWT_ASSERT_APPKIT_THREAD; self.isMinimizing = YES; + + JNIEnv *env = [ThreadUtilities getJNIEnv]; + jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env]; + if (platformWindow != NULL) { + static JNF_MEMBER_CACHE(jm_windowWillMiniaturize, jc_CPlatformWindow, "windowWillMiniaturize", "()V"); + JNFCallVoidMethod(env, platformWindow, jm_windowWillMiniaturize); + (*env)->DeleteLocalRef(env, platformWindow); + } // Excplicitly make myself a key window to avoid possible // negative visual effects during iconify operation [self.nsWindow makeKeyAndOrderFront:self.nsWindow]; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -730,18 +730,47 @@ // to use it if the data layout is component type. if (iccProfileField != null && itsRaw.getColorModel() instanceof ComponentColorModel) { - // Create a ColorSpace from the profile. - byte[] iccProfileValue = iccProfileField.getAsBytes(); - ICC_Profile iccProfile - = ICC_Profile.getInstance(iccProfileValue); - ICC_ColorSpace iccColorSpace - = new ICC_ColorSpace(iccProfile); - // Get the raw sample and color information. ColorModel cmRaw = itsRaw.getColorModel(); ColorSpace csRaw = cmRaw.getColorSpace(); SampleModel smRaw = itsRaw.getSampleModel(); + ColorSpace iccColorSpace = null; + try { + // Create a ColorSpace from the profile. + byte[] iccProfileValue = iccProfileField.getAsBytes(); + ICC_Profile iccProfile + = ICC_Profile.getInstance(iccProfileValue); + iccColorSpace = new ICC_ColorSpace(iccProfile); + + // Workaround for JDK-8145241: test a conversion and fall + // back to a standard ColorSpace if it fails. This + // workaround could be removed if JDK-8145241 is fixed. + float[] rgb = + iccColorSpace.toRGB(new float[] {1.0F, 1.0F, 1.0F}); + } catch (Exception iccProfileException) { + processWarningOccurred("Superseding bad ICC profile: " + + iccProfileException.getMessage()); + + if (iccColorSpace != null) { + switch (iccColorSpace.getType()) { + case ColorSpace.TYPE_GRAY: + iccColorSpace = + ColorSpace.getInstance(ColorSpace.CS_GRAY); + break; + case ColorSpace.TYPE_RGB: + iccColorSpace = + ColorSpace.getInstance(ColorSpace.CS_sRGB); + break; + default: + iccColorSpace = csRaw; + break; + } + } else { + iccColorSpace = csRaw; + } + } + // Get the number of samples per pixel and the number // of color components. int numBands = smRaw.getNumBands(); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/java/beans/AppletInitializer.java --- a/jdk/src/java.desktop/share/classes/java/beans/AppletInitializer.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/java/beans/AppletInitializer.java Wed Jul 05 22:42:01 2017 +0200 @@ -30,21 +30,20 @@ import java.beans.beancontext.BeanContext; /** - *

    * This interface is designed to work in collusion with java.beans.Beans.instantiate. * The interface is intended to provide mechanism to allow the proper * initialization of JavaBeans that are also Applets, during their * instantiation by java.beans.Beans.instantiate(). - *

    * * @see java.beans.Beans#instantiate * * @since 1.2 * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ - - -@SuppressWarnings("deprecation") +@Deprecated(since = "9") public interface AppletInitializer { /** @@ -74,7 +73,6 @@ * @param bCtxt The BeanContext intended for this Applet, or * null. */ - void initialize(Applet newAppletBean, BeanContext bCtxt); /** @@ -86,6 +84,5 @@ * * @param newApplet The newly instantiated JavaBean */ - void activate(Applet newApplet); } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/java/beans/Beans.java --- a/jdk/src/java.desktop/share/classes/java/beans/Beans.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/java/beans/Beans.java Wed Jul 05 22:42:01 2017 +0200 @@ -97,8 +97,10 @@ * @exception IOException if an I/O error occurs. * @since 1.2 */ - - public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException { + @SuppressWarnings("deprecation") + public static Object instantiate(ClassLoader cls, String beanName, + BeanContext beanContext) + throws IOException, ClassNotFoundException { return Beans.instantiate(cls, beanName, beanContext, null); } @@ -153,10 +155,18 @@ * object could not be found. * @exception IOException if an I/O error occurs. * @since 1.2 + * + * @deprecated It is recommended to use + * {@link #instantiate(ClassLoader, String, BeanContext)}, + * because the Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ - @SuppressWarnings("deprecation") - public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer) - throws IOException, ClassNotFoundException { + @Deprecated(since = "9") + public static Object instantiate(ClassLoader cls, String beanName, + BeanContext beanContext, + AppletInitializer initializer) + throws IOException, ClassNotFoundException { InputStream ins; ObjectInputStream oins = null; @@ -501,7 +511,7 @@ * Package private support class. This provides a default AppletContext * for beans which are applets. */ -@SuppressWarnings("deprecation") +@Deprecated(since = "9") class BeansAppletContext implements AppletContext { Applet target; Hashtable imageCache = new Hashtable<>(); @@ -586,7 +596,7 @@ * Package private support class. This provides an AppletStub * for beans which are applets. */ -@SuppressWarnings("deprecation") +@Deprecated(since = "9") class BeansAppletStub implements AppletStub { transient boolean active; transient Applet target; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/PopupFactory.java --- a/jdk/src/java.desktop/share/classes/javax/swing/PopupFactory.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/PopupFactory.java Wed Jul 05 22:42:01 2017 +0200 @@ -260,6 +260,7 @@ * Obtains the appropriate Popup based on * popupType. */ + @SuppressWarnings("deprecation") private Popup getPopup(Component owner, Component contents, int ownerX, int ownerY, int popupType) { if (GraphicsEnvironment.isHeadless()) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java --- a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java Wed Jul 05 22:42:01 2017 +0200 @@ -525,8 +525,12 @@ * @param h Height of the region to repaint * @see JApplet#repaint * @since 1.6 + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ - @SuppressWarnings("deprecation") + @Deprecated(since = "9") public void addDirtyRegion(Applet applet, int x, int y, int w, int h) { addDirtyRegion0(applet, x, y, w, h); } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java --- a/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java Wed Jul 05 22:42:01 2017 +0200 @@ -380,6 +380,12 @@ // print the current section of the table g2d.translate(-clip.x, -clip.y); g2d.clip(clip); + + // set a property so that BasicTableUI#paint can know JTable printMode + // is FIT_WIDTH since TablePrintable.printMode is not accessible from BasicTableUI + if (printMode == JTable.PrintMode.FIT_WIDTH) { + table.putClientProperty("Table.printMode", JTable.PrintMode.FIT_WIDTH); + } table.print(g2d); // restore the original transform and clip @@ -407,8 +413,18 @@ for(int visrow = rMin; visrow < rMax; visrow++) { rowHeight += table.getRowHeight(visrow); } - g2d.drawRect(0, 0, visibleBounds.width, hclip.height + rowHeight); + // If PrintMode is FIT_WIDTH, then draw rect for entire column width while + // printing irrespective of how many columns are visible in console + if (printMode == JTable.PrintMode.FIT_WIDTH) { + g2d.drawRect(0, 0, clip.width, hclip.height + rowHeight); + } else { + g2d.drawRect(0, 0, visibleBounds.width, hclip.height + rowHeight); + } + // clear the property + if (printMode == JTable.PrintMode.FIT_WIDTH) { + table.putClientProperty("Table.printMode", null); + } // dispose the graphics copy g2d.dispose(); @@ -534,5 +550,4 @@ } while (clip.width + colWidth <= pw); } - } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java Wed Jul 05 22:42:01 2017 +0200 @@ -1812,12 +1812,12 @@ } boolean ltr = table.getComponentOrientation().isLeftToRight(); - + Point upperLeft, lowerRight; // compute the visible part of table which needs to be painted Rectangle visibleBounds = clip.intersection(bounds); - Point upperLeft = visibleBounds.getLocation(); - Point lowerRight = new Point(visibleBounds.x + visibleBounds.width - 1, - visibleBounds.y + visibleBounds.height - 1); + upperLeft = visibleBounds.getLocation(); + lowerRight = new Point(visibleBounds.x + visibleBounds.width - 1, + visibleBounds.y + visibleBounds.height - 1); int rMin = table.rowAtPoint(upperLeft); int rMax = table.rowAtPoint(lowerRight); @@ -1834,6 +1834,18 @@ rMax = table.getRowCount()-1; } + // For FIT_WIDTH, all columns should be printed irrespective of + // how many columns are visible. So, we used clip which is already set to + // total col width instead of visible region + // Since JTable.PrintMode is not accessible + // from here, we aet "Table.printMode" in TablePrintable#print and + // access from here. + Object printMode = table.getClientProperty("Table.printMode"); + if ((printMode == JTable.PrintMode.FIT_WIDTH)) { + upperLeft = clip.getLocation(); + lowerRight = new Point(clip.x + clip.width - 1, + clip.y + clip.height - 1); + } int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight); int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft); // This should never happen. @@ -2018,7 +2030,7 @@ int y = damagedArea.y; for (int row = rMin; row <= rMax; row++) { y += table.getRowHeight(row); - g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1); + SwingUtilities2.drawHLine(g, damagedArea.x, tableWidth - 1, y - 1); } } if (table.getShowVerticalLines()) { @@ -2030,14 +2042,14 @@ for (int column = cMin; column <= cMax; column++) { int w = cm.getColumn(column).getWidth(); x += w; - g.drawLine(x - 1, 0, x - 1, tableHeight - 1); + SwingUtilities2.drawVLine(g, x - 1, 0, tableHeight - 1); } } else { x = damagedArea.x; for (int column = cMax; column >= cMin; column--) { int w = cm.getColumn(column).getWidth(); x += w; - g.drawLine(x - 1, 0, x - 1, tableHeight - 1); + SwingUtilities2.drawVLine(g, x - 1, 0, tableHeight - 1); } } } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java Wed Jul 05 22:42:01 2017 +0200 @@ -27,10 +27,7 @@ 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 @@ -332,22 +329,6 @@ 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); - } - }); - } + private final boolean drawEchoCharacterOverridden = + getFPMethodOverridden(getClass(), "drawEchoCharacter", FPMethodArgs.GNNC); } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java Wed Jul 05 22:42:01 2017 +0200 @@ -32,6 +32,8 @@ import java.util.Objects; import javax.swing.event.*; import java.lang.reflect.Module; +import java.lang.ref.SoftReference; +import java.util.HashMap; /** * Implements View interface for a simple multi-line text view @@ -818,10 +820,45 @@ return w; } - static boolean isFPMethodOverriden(String method, - Class cls, - Class[] intTypes, - Class[] fpTypes) + static boolean getFPMethodOverridden(Class cls, String method, + FPMethodArgs methodArgs) { + HashMap map = null; + boolean initialized = methodsOverriddenMapRef != null + && (map = methodsOverriddenMapRef.get()) != null; + + if (!initialized) { + map = new HashMap<>(); + methodsOverriddenMapRef = new SoftReference<>(map); + } + + FPMethodItem key = new FPMethodItem(cls, method); + Boolean isFPMethodOverridden = map.get(key); + if (isFPMethodOverridden == null) { + isFPMethodOverridden = checkFPMethodOverridden(cls, method, methodArgs); + map.put(key, isFPMethodOverridden); + } + return isFPMethodOverridden; + } + + private static boolean checkFPMethodOverridden(final Class className, + final String methodName, + final FPMethodArgs methodArgs) { + + return AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + return isFPMethodOverridden(methodName, className, + methodArgs.getMethodArguments(false), + methodArgs.getMethodArguments(true)); + } + }); + } + + private static boolean isFPMethodOverridden(String method, + Class cls, + Class[] intTypes, + Class[] fpTypes) { Module thisModule = PlainView.class.getModule(); while (!thisModule.equals(cls.getModule())) { @@ -840,6 +877,57 @@ return true; } + enum FPMethodArgs { + + IGNN, + IIGNN, + GNNII, + GNNC; + + public Class[] getMethodArguments(boolean isFPType) { + Class N = (isFPType) ? Float.TYPE : Integer.TYPE; + Class G = (isFPType) ? Graphics2D.class : Graphics.class; + switch (this) { + case IGNN: + return new Class[]{Integer.TYPE, G, N, N}; + case IIGNN: + return new Class[]{Integer.TYPE, Integer.TYPE, G, N, N}; + case GNNII: + return new Class[]{G, N, N, Integer.TYPE, Integer.TYPE}; + case GNNC: + return new Class[]{G, N, N, Character.TYPE}; + default: + throw new RuntimeException("Unknown method arguments!"); + } + } + } + + private static class FPMethodItem { + + final Class className; + final String methodName; + + public FPMethodItem(Class className, String methodName) { + this.className = className; + this.methodName = methodName; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FPMethodItem) { + FPMethodItem that = (FPMethodItem) obj; + return this.className.equals(that.className) + && this.methodName.equals(that.methodName); + } + return false; + } + + @Override + public int hashCode() { + return 31 * methodName.hashCode() + className.hashCode(); + } + } + // --- member variables ----------------------------------------------- /** @@ -878,46 +966,13 @@ */ 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; - } + private static SoftReference> methodsOverriddenMapRef; + final boolean drawLineOverridden = + getFPMethodOverridden(getClass(), "drawLine", FPMethodArgs.IGNN); + final boolean drawSelectedTextOverridden = + getFPMethodOverridden(getClass(), "drawSelectedText", FPMethodArgs.GNNII); + final boolean drawUnselectedTextOverridden = + getFPMethodOverridden(getClass(), "drawUnselectedText", FPMethodArgs.GNNII); + final boolean useFloatingPointAPI = + drawUnselectedTextOverridden || drawSelectedTextOverridden; } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Wed Jul 05 22:42:01 2017 +0200 @@ -28,10 +28,9 @@ import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.lang.ref.SoftReference; -import java.security.AccessController; -import java.security.PrivilegedAction; import javax.swing.event.*; -import static javax.swing.text.PlainView.isFPMethodOverriden; +import static javax.swing.text.PlainView.FPMethodArgs.*; +import static javax.swing.text.PlainView.getFPMethodOverridden; /** * View of plain text (text with only one font and color) @@ -989,46 +988,12 @@ 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; - } + private final boolean drawLineOverridden = + getFPMethodOverridden(getClass(), "drawLine", IIGNN); + private final boolean drawSelectedTextOverridden = + getFPMethodOverridden(getClass(), "drawSelectedText", GNNII); + private final boolean drawUnselectedTextOverridden = + getFPMethodOverridden(getClass(), "drawUnselectedText", GNNII); + private final boolean useFloatingPointAPI = + drawUnselectedTextOverridden || drawSelectedTextOverridden; } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletEvent.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletEvent.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletEvent.java Wed Jul 05 22:42:01 2017 +0200 @@ -32,8 +32,13 @@ * AppletEvent class. * * @author Sunita Mani + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ @SuppressWarnings("serial") // JDK-implementation class +@Deprecated(since = "9") public class AppletEvent extends EventObject { private Object arg; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletEventMulticaster.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletEventMulticaster.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletEventMulticaster.java Wed Jul 05 22:42:01 2017 +0200 @@ -36,7 +36,12 @@ * responsible for dispatching events to them. * * @author Sunita Mani + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ +@Deprecated(since = "9") public class AppletEventMulticaster implements AppletListener { private final AppletListener a, b; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletIOException.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletIOException.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletIOException.java Wed Jul 05 22:42:01 2017 +0200 @@ -31,10 +31,14 @@ * An applet IO exception. * * @author Koji Uno + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ @SuppressWarnings("serial") // JDK implementation class -public -class AppletIOException extends IOException { +@Deprecated(since = "9") +public class AppletIOException extends IOException { private String key = null; private Object msgobj = null; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletIllegalArgumentException.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletIllegalArgumentException.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletIllegalArgumentException.java Wed Jul 05 22:42:01 2017 +0200 @@ -29,10 +29,14 @@ * An applet security exception. * * @author Arthur van Hoff + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ @SuppressWarnings("serial") // JDK implementation class -public -class AppletIllegalArgumentException extends IllegalArgumentException { +@Deprecated(since = "9") +public class AppletIllegalArgumentException extends IllegalArgumentException { private String key = null; public AppletIllegalArgumentException(String key) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletImageRef.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletImageRef.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletImageRef.java Wed Jul 05 22:42:01 2017 +0200 @@ -31,6 +31,7 @@ import sun.awt.image.URLImageSource; import java.net.URL; +@Deprecated(since = "9") class AppletImageRef { private SoftReference soft = null; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletListener.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletListener.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletListener.java Wed Jul 05 22:42:01 2017 +0200 @@ -32,8 +32,12 @@ * by objects interested in AppletEvents. * * @author Sunita Mani + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ - +@Deprecated(since = "9") public interface AppletListener extends EventListener { public void appletStateChanged(AppletEvent e); } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletObjectInputStream.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletObjectInputStream.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletObjectInputStream.java Wed Jul 05 22:42:01 2017 +0200 @@ -34,8 +34,12 @@ /** * This subclass of ObjectInputStream delegates loading of classes to * an existing ClassLoader. + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ - +@Deprecated(since = "9") class AppletObjectInputStream extends ObjectInputStream { private AppletClassLoader loader; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Wed Jul 05 22:42:01 2017 +0200 @@ -52,9 +52,14 @@ * thread group to call the applet's init(), start(), stop(), and * destroy() methods. * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. + * * @author Arthur van Hoff */ -@SuppressWarnings({"serial", "deprecation"}) // JDK implementation class +@SuppressWarnings({"serial"}) // JDK implementation class +@Deprecated(since = "9") public abstract class AppletPanel extends Panel implements AppletStub, Runnable { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletProps.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletProps.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletProps.java Wed Jul 05 22:42:01 2017 +0200 @@ -36,6 +36,7 @@ import sun.security.action.*; @SuppressWarnings("serial") // JDK implementation class +@Deprecated(since = "9") class AppletProps extends Frame { TextField proxyHost; @@ -197,6 +198,7 @@ /* 4066432 */ /* Dialog class to display property-related errors to user */ @SuppressWarnings("serial") // JDK implementation class +@Deprecated(since = "9") class AppletPropsErrorDialog extends Dialog { @SuppressWarnings("deprecation") public AppletPropsErrorDialog(Frame parent, String title, String message, diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java Wed Jul 05 22:42:01 2017 +0200 @@ -43,6 +43,7 @@ * A frame to show the applet tag in. */ @SuppressWarnings("serial") // JDK-implementation class +@Deprecated(since = "9") final class TextFrame extends Frame { /** @@ -91,6 +92,7 @@ /** * Lets us construct one using unix-style one shot behaviors. */ +@Deprecated(since = "9") final class StdAppletViewerFactory implements AppletViewerFactory { @Override @@ -116,8 +118,13 @@ * AppletViewer Tags. * (The document named appletviewertags.html in the JDK's docs/tooldocs directory, * once the JDK docs have been installed.) + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ -@SuppressWarnings({"serial", "deprecation"}) // JDK-implementation class +@SuppressWarnings({"serial"}) // JDK-implementation class +@Deprecated(since = "9") public class AppletViewer extends Frame implements AppletContext, Printable { /** @@ -146,7 +153,7 @@ */ AppletViewerFactory factory; - + @Deprecated(since = "9") private final class UserActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent evt) { @@ -219,6 +226,7 @@ } }; + @Deprecated(since = "9") class AppletEventListener implements AppletListener { final Frame frame; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletViewerFactory.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerFactory.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerFactory.java Wed Jul 05 22:42:01 2017 +0200 @@ -33,8 +33,8 @@ import java.net.URL; import java.awt.MenuBar; -public -interface AppletViewerFactory { +@Deprecated(since = "9") +public interface AppletViewerFactory { public AppletViewer createAppletViewer(int x, int y, URL doc, Hashtable atts); public MenuBar getBaseMenuBar(); diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/AppletViewerPanel.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerPanel.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerPanel.java Wed Jul 05 22:42:01 2017 +0200 @@ -40,7 +40,12 @@ * destroy() methods. * * @author Arthur van Hoff + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ +@Deprecated(since = "9") class AppletViewerPanel extends AppletPanel { /* Are we debugging? */ diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/applet/Main.java --- a/jdk/src/java.desktop/share/classes/sun/applet/Main.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/applet/Main.java Wed Jul 05 22:42:01 2017 +0200 @@ -39,7 +39,12 @@ /** * The main entry point into AppletViewer. + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ +@Deprecated(since = "9") public class Main { /** * The file which contains all of the AppletViewer specific properties. diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java --- a/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java Wed Jul 05 22:42:01 2017 +0200 @@ -496,10 +496,14 @@ * Checks if the component is in an EmbeddedFrame. If so, * returns the applet found in the hierarchy or null if * not found. - * @return the parent applet or {@ null} + * @return the parent applet or {@code null} * @since 1.6 + * + * @deprecated The Applet API is deprecated. See the + * java.applet package + * documentation for further information. */ - @SuppressWarnings("deprecation") + @Deprecated(since = "9") public static Applet getAppletIfAncestorOf(Component comp) { Container parent = comp.getParent(); Applet applet = null; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c --- a/jdk/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c Wed Jul 05 22:42:01 2017 +0200 @@ -2419,7 +2419,7 @@ case sun_awt_image_IntegerComponentRaster_TYPE_INT_8BIT_SAMPLES: if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 4)) && SAFE_TO_ALLOC_2(width, 4) && - SAFE_TO_ALLOC_3(height, rasterP->scanlineStride, 4))) + SAFE_TO_ALLOC_3(rasterP->scanlineStride, height, 4))) { return -1; } @@ -2428,7 +2428,7 @@ if (offset < 0 || offset >= dataSize || width > rasterP->scanlineStride || - height * rasterP->scanlineStride * 4 > dataSize - offset) + ((width + (height - 1) * rasterP->scanlineStride) * 4) > dataSize - offset) { // raster data buffer is too short return -1; @@ -2446,7 +2446,7 @@ return 0; case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_SAMPLES: if (!(SAFE_TO_ALLOC_2(width, rasterP->numBands) && - SAFE_TO_ALLOC_2(height, rasterP->scanlineStride))) + SAFE_TO_ALLOC_2(rasterP->scanlineStride, height))) { return -1; } @@ -2455,7 +2455,8 @@ if (offset < 0 || offset >= dataSize || width * rasterP->numBands > rasterP->scanlineStride || - height * rasterP->scanlineStride > dataSize - offset) + ((width * rasterP->numBands) + + (height - 1) * rasterP->scanlineStride) > dataSize - offset) { // raster data buffer is too short return -1; @@ -2474,7 +2475,7 @@ case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_SAMPLES: if (!((rasterP->chanOffsets[0] == 0 || SAFE_TO_ALLOC_2(rasterP->chanOffsets[0], 2)) && SAFE_TO_ALLOC_3(width, rasterP->numBands, 2) && - SAFE_TO_ALLOC_3(height, rasterP->scanlineStride, 2))) + SAFE_TO_ALLOC_3(rasterP->scanlineStride, height, 2))) { return -1; } @@ -2483,7 +2484,8 @@ if (offset < 0 || offset >= dataSize || width * rasterP->numBands > rasterP->scanlineStride || - height * rasterP->scanlineStride * 2 > dataSize - offset) + (((width * rasterP->numBands) + + (height - 1) * rasterP->scanlineStride)) * 2 > dataSize - offset) { // raster data buffer is too short return -1; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/share/native/libmlib_image/safe_alloc.h --- a/jdk/src/java.desktop/share/native/libmlib_image/safe_alloc.h Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/share/native/libmlib_image/safe_alloc.h Wed Jul 05 22:42:01 2017 +0200 @@ -35,10 +35,10 @@ */ #define SAFE_TO_ALLOC_2(c, sz) \ (((c) > 0) && ((sz) > 0) && \ - ((0xffffffffu / ((juint)(c))) > ((juint)(sz)))) + ((0x7fffffff / (c)) > (sz))) #define SAFE_TO_ALLOC_3(w, h, sz) \ (((w) > 0) && ((h) > 0) && ((sz) > 0) && \ - (((0xffffffffu / ((juint)(w))) / ((juint)(h))) > ((juint)(sz)))) + (((0x7fffffff / (w)) / (h)) > (sz))) #endif // __SAFE_ALLOC_H__ diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java Wed Jul 05 22:42:01 2017 +0200 @@ -51,9 +51,9 @@ boolean insets_corrected; XIconWindow iconWindow; - WindowDimensions dimensions; + volatile WindowDimensions dimensions; XContentWindow content; - Insets currentInsets; + volatile Insets currentInsets; XFocusProxyWindow focusProxy; static final Map,Insets> lastKnownInsets = Collections.synchronizedMap(new HashMap<>()); @@ -106,7 +106,7 @@ // The lines that follow need to be in a postInit, so they // happen after the X window is created. - initResizability(); + setResizable(winAttr.initialResizability); XWM.requestWMExtents(getWindow()); content = XContentWindow.createContent(this); @@ -130,7 +130,12 @@ public void updateMinimumSize() { super.updateMinimumSize(); - updateMinSizeHints(); + XToolkit.awtLock(); + try { + updateMinSizeHints(); + } finally { + XToolkit.awtUnlock(); + } } private void updateMinSizeHints() { @@ -193,8 +198,13 @@ if (log.isLoggable(PlatformLogger.Level.FINE)) { log.fine("Title is " + title); } - winAttr.title = title; - updateWMName(); + XToolkit.awtLock(); + try { + winAttr.title = title; + updateWMName(); + } finally { + XToolkit.awtUnlock(); + } } protected String getWMName() { @@ -206,10 +216,10 @@ } void updateWMName() { - super.updateWMName(); - String name = getWMName(); XToolkit.awtLock(); try { + super.updateWMName(); + String name = getWMName(); if (name == null || name.trim().equals("")) { name = "Java"; } @@ -304,6 +314,8 @@ if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) { currentInsets = new Insets(0, 0, 0, 0); wm_set_insets = null; + } else { + insets_corrected = false; } } @@ -330,7 +342,7 @@ if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) { getWMSetInsets(XAtom.get(ev.get_atom())); } else { - if(!isReparented()) { + if (!isReparented()) { return; } wm_set_insets = null; @@ -377,137 +389,127 @@ insLog.fine(xe.toString()); } reparent_serial = xe.get_serial(); - XToolkit.awtLock(); - try { - long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); + long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); + + if (isEmbedded()) { + setReparented(true); + insets_corrected = true; + return; + } + if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { + setReparented(true); + insets_corrected = true; + reshape(dimensions, SET_SIZE, false); + } else if (xe.get_parent() == root) { + configure_seen = false; + insets_corrected = false; - if (isEmbedded()) { - setReparented(true); - insets_corrected = true; + /* + * We can be repareted to root for two reasons: + * . setVisible(false) + * . WM exited + */ + if (isVisible()) { /* WM exited */ + /* Work around 4775545 */ + XWM.getWM().unshadeKludge(this); + insLog.fine("- WM exited"); + } else { + insLog.fine(" - reparent due to hide"); + } + } else { /* reparented to WM frame, figure out our insets */ + setReparented(true); + insets_corrected = false; + if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) { return; } - Component t = target; - if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { - setReparented(true); - insets_corrected = true; - reshape(dimensions, SET_SIZE, false); - } else if (xe.get_parent() == root) { - configure_seen = false; - insets_corrected = false; - /* - * We can be repareted to root for two reasons: - * . setVisible(false) - * . WM exited - */ - if (isVisible()) { /* WM exited */ - /* Work around 4775545 */ - XWM.getWM().unshadeKludge(this); - insLog.fine("- WM exited"); - } else { - insLog.fine(" - reparent due to hide"); + // Check if we have insets provided by the WM + Insets correctWM = getWMSetInsets(null); + if (correctWM != null) { + if (insLog.isLoggable(PlatformLogger.Level.FINER)) { + insLog.finer("wm-provided insets {0}", correctWM); } - } else { /* reparented to WM frame, figure out our insets */ - setReparented(true); - insets_corrected = false; - if (XWM.getWMID() == XWM.UNITY_COMPIZ_WM) { + // If these insets are equal to our current insets - no actions are necessary + Insets dimInsets = dimensions.getInsets(); + if (correctWM.equals(dimInsets)) { + insLog.finer("Insets are the same as estimated - no additional reshapes necessary"); + no_reparent_artifacts = true; + insets_corrected = true; + applyGuessedInsets(); return; } + } else { + correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent()); + if (correctWM != null) { + correctWM = copyAndScaleDown(correctWM); + } - // Check if we have insets provided by the WM - Insets correctWM = getWMSetInsets(null); - if (correctWM != null) { - if (insLog.isLoggable(PlatformLogger.Level.FINER)) { - insLog.finer("wm-provided insets {0}", correctWM); - } - // If these insets are equal to our current insets - no actions are necessary - Insets dimInsets = dimensions.getInsets(); - if (correctWM.equals(dimInsets)) { - insLog.finer("Insets are the same as estimated - no additional reshapes necessary"); - no_reparent_artifacts = true; - insets_corrected = true; - applyGuessedInsets(); - return; - } - } else { - correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent()); + if (insLog.isLoggable(PlatformLogger.Level.FINER)) { if (correctWM != null) { - correctWM = copyAndScaleDown(correctWM); - } - - if (insLog.isLoggable(PlatformLogger.Level.FINER)) { - if (correctWM != null) { - insLog.finer("correctWM {0}", correctWM); - } else { - insLog.finer("correctWM insets are not available, waiting for configureNotify"); - } + insLog.finer("correctWM {0}", correctWM); + } else { + insLog.finer("correctWM insets are not available, waiting for configureNotify"); } } + } - if (correctWM != null) { - handleCorrectInsets(correctWM); - } + if (correctWM != null) { + handleCorrectInsets(correctWM); } - } finally { - XToolkit.awtUnlock(); } } - protected void handleCorrectInsets(Insets correctWM) { - XToolkit.awtLock(); - try { - /* - * Ok, now see if we need adjust window size because - * initial insets were wrong (most likely they were). - */ - Insets correction = difference(correctWM, currentInsets); - if (insLog.isLoggable(PlatformLogger.Level.FINEST)) { - insLog.finest("Corrention {0}", correction); - } - if (!isNull(correction)) { - currentInsets = copy(correctWM); - applyGuessedInsets(); + private void handleCorrectInsets(Insets correctWM) { + /* + * Ok, now see if we need adjust window size because + * initial insets were wrong (most likely they were). + */ + Insets correction = difference(correctWM, currentInsets); + if (insLog.isLoggable(PlatformLogger.Level.FINEST)) { + insLog.finest("Corrention {0}", correction); + } + if (!isNull(correction)) { + currentInsets = copy(correctWM); + applyGuessedInsets(); - //Fix for 6318109: PIT: Min Size is not honored properly when a - //smaller size is specified in setSize(), XToolkit - //update minimum size hints - updateMinSizeHints(); - } - if (insLog.isLoggable(PlatformLogger.Level.FINER)) { - insLog.finer("Dimensions before reparent: " + dimensions); - } - - dimensions.setInsets(getRealInsets()); - insets_corrected = true; + //Fix for 6318109: PIT: Min Size is not honored properly when a + //smaller size is specified in setSize(), XToolkit + //update minimum size hints + updateMinSizeHints(); + } + if (insLog.isLoggable(PlatformLogger.Level.FINER)) { + insLog.finer("Dimensions before reparent: " + dimensions); + } + WindowDimensions newDimensions = new WindowDimensions(dimensions); + newDimensions.setInsets(getRealInsets()); + dimensions = newDimensions; + insets_corrected = true; - if (isMaximized()) { - return; - } + if (isMaximized()) { + return; + } - /* - * If this window has been sized by a pack() we need - * to keep the interior geometry intact. Since pack() - * computed width and height with wrong insets, we - * must adjust the target dimensions appropriately. - */ - if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) { - reshape(dimensions, SET_BOUNDS, false); - } else { - reshape(dimensions, SET_SIZE, false); - } - } finally { - XToolkit.awtUnlock(); + /* + * If this window has been sized by a pack() we need + * to keep the interior geometry intact. Since pack() + * computed width and height with wrong insets, we + * must adjust the target dimensions appropriately. + */ + if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) { + reshape(dimensions, SET_BOUNDS, false); + } else { + reshape(dimensions, SET_SIZE, false); } } - public void handleMoved(WindowDimensions dims) { + void handleMoved(WindowDimensions dims) { Point loc = dims.getLocation(); AWTAccessor.getComponentAccessor().setLocation(target, loc.x, loc.y); postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); } - protected Insets guessInsets() { + private Insets guessInsets() { if (isEmbedded() || isTargetUndecorated()) { return new Insets(0, 0, 0, 0); } else { @@ -532,16 +534,7 @@ currentInsets = copy(guessed); } - public void revalidate() { - XToolkit.executeOnEventHandlerThread(target, new Runnable() { - public void run() { - target.invalidate(); - target.validate(); - } - }); - } - - Insets getRealInsets() { + private Insets getRealInsets() { if (isNull(currentInsets)) { applyGuessedInsets(); } @@ -578,7 +571,7 @@ // Coordinates are that of the target // Called only on Toolkit thread - public void reshape(WindowDimensions newDimensions, int op, + private void reshape(WindowDimensions newDimensions, int op, boolean userReshape) { if (insLog.isLoggable(PlatformLogger.Level.FINE)) { @@ -599,81 +592,75 @@ } newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet()); } - XToolkit.awtLock(); - try { - if (!isReparented() || !isVisible()) { - if (insLog.isLoggable(PlatformLogger.Level.FINE)) { - insLog.fine("- not reparented({0}) or not visible({1}), default reshape", - Boolean.valueOf(isReparented()), Boolean.valueOf(visible)); - } - - // Fix for 6323293. - // This actually is needed to preserve compatibility with previous releases - - // some of licensees are expecting componentMoved event on invisible one while - // its location changes. - Point oldLocation = getLocation(); + if (!isReparented() || !isVisible()) { + if (insLog.isLoggable(PlatformLogger.Level.FINE)) { + insLog.fine("- not reparented({0}) or not visible({1}), default reshape", + Boolean.valueOf(isReparented()), Boolean.valueOf(visible)); + } - Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target), - AWTAccessor.getComponentAccessor().getY(target)); - - if (!newLocation.equals(oldLocation)) { - handleMoved(newDimensions); - } + // Fix for 6323293. + // This actually is needed to preserve compatibility with previous releases - + // some of licensees are expecting componentMoved event on invisible one while + // its location changes. + Point oldLocation = getLocation(); - dimensions = new WindowDimensions(newDimensions); - updateSizeHints(dimensions); - Rectangle client = dimensions.getClientRect(); - checkShellRect(client); - setShellBounds(client); - if (content != null && - !content.getSize().equals(newDimensions.getSize())) - { - reconfigureContentWindow(newDimensions); - } - return; + Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target), + AWTAccessor.getComponentAccessor().getY(target)); + + if (!newLocation.equals(oldLocation)) { + handleMoved(newDimensions); } - int wm = XWM.getWMID(); - updateChildrenSizes(); - applyGuessedInsets(); - - Rectangle shellRect = newDimensions.getClientRect(); - - if (gravityBug()) { - Insets in = newDimensions.getInsets(); - shellRect.translate(in.left, in.top); + dimensions = new WindowDimensions(newDimensions); + updateSizeHints(dimensions); + Rectangle client = dimensions.getClientRect(); + checkShellRect(client); + setShellBounds(client); + if (content != null && + !content.getSize().equals(newDimensions.getSize())) + { + reconfigureContentWindow(newDimensions); } + return; + } - if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { - shellRect.setLocation(0, 0); - } + updateChildrenSizes(); + applyGuessedInsets(); - checkShellRectSize(shellRect); - if (!isEmbedded()) { - checkShellRectPos(shellRect); - } + Rectangle shellRect = newDimensions.getClientRect(); + + if (gravityBug()) { + Insets in = newDimensions.getInsets(); + shellRect.translate(in.left, in.top); + } - op = op & ~NO_EMBEDDED_CHECK; + if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { + shellRect.setLocation(0, 0); + } - if (op == SET_LOCATION) { - setShellPosition(shellRect); - } else if (isResizable()) { - if (op == SET_BOUNDS) { - setShellBounds(shellRect); - } else { - setShellSize(shellRect); - } + checkShellRectSize(shellRect); + if (!isEmbedded()) { + checkShellRectPos(shellRect); + } + + op = op & ~NO_EMBEDDED_CHECK; + + if (op == SET_LOCATION) { + setShellPosition(shellRect); + } else if (isResizable()) { + if (op == SET_BOUNDS) { + setShellBounds(shellRect); } else { - XWM.setShellNotResizable(this, newDimensions, shellRect, true); - if (op == SET_BOUNDS) { - setShellPosition(shellRect); - } + setShellSize(shellRect); } + } else { + XWM.setShellNotResizable(this, newDimensions, shellRect, true); + if (op == SET_BOUNDS) { + setShellPosition(shellRect); + } + } - reconfigureContentWindow(newDimensions); - } finally { - XToolkit.awtUnlock(); - } + reconfigureContentWindow(newDimensions); } /** @@ -682,8 +669,6 @@ private void reshape(int x, int y, int width, int height, int operation, boolean userReshape) { - Rectangle newRec; - boolean setClient = false; WindowDimensions dims = new WindowDimensions(dimensions); switch (operation & (~NO_EMBEDDED_CHECK)) { case SET_LOCATION: @@ -726,7 +711,12 @@ */ public void setBounds(int x, int y, int width, int height, int op) { // TODO: Rewrite with WindowDimensions - reshape(x, y, width, height, op, true); + XToolkit.awtLock(); + try { + reshape(x, y, width, height, op, true); + } finally { + XToolkit.awtUnlock(); + } validateSurface(); } @@ -861,81 +851,74 @@ checkShellRectPos(shellRect); } - public void setShellBounds(Rectangle rec) { + private void setShellBounds(Rectangle rec) { if (insLog.isLoggable(PlatformLogger.Level.FINE)) { insLog.fine("Setting shell bounds on " + this + " to " + rec); } - XToolkit.awtLock(); - try { - updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(), - scaleUp(rec.x), scaleUp(rec.y), - scaleUp(rec.width), scaleUp(rec.height)); - } - finally { - XToolkit.awtUnlock(); - } + updateSizeHints(rec.x, rec.y, rec.width, rec.height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.x), scaleUp(rec.y), + scaleUp(rec.width), scaleUp(rec.height)); } - public void setShellSize(Rectangle rec) { + + private void setShellSize(Rectangle rec) { if (insLog.isLoggable(PlatformLogger.Level.FINE)) { insLog.fine("Setting shell size on " + this + " to " + rec); } - XToolkit.awtLock(); - try { - updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), - scaleUp(rec.width), scaleUp(rec.height)); - } - finally { - XToolkit.awtUnlock(); - } + updateSizeHints(rec.x, rec.y, rec.width, rec.height); + XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.width), scaleUp(rec.height)); } - public void setShellPosition(Rectangle rec) { + + private void setShellPosition(Rectangle rec) { if (insLog.isLoggable(PlatformLogger.Level.FINE)) { insLog.fine("Setting shell position on " + this + " to " + rec); } - XToolkit.awtLock(); - try { - updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), - scaleUp(rec.x), scaleUp(rec.y)); - } - finally { - XToolkit.awtUnlock(); - } + updateSizeHints(rec.x, rec.y, rec.width, rec.height); + XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.x), scaleUp(rec.y)); } - void initResizability() { - setResizable(winAttr.initialResizability); - } public void setResizable(boolean resizable) { - int fs = winAttr.functions; - if (!isResizable() && resizable) { - resetWMSetInsets(); - if (!isEmbedded()) { - setReparented(false); - } - winAttr.isResizable = resizable; - if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { - fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); - } else { - fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); + XToolkit.awtLock(); + try { + int fs = winAttr.functions; + if (!isResizable() && resizable) { + resetWMSetInsets(); + if (!isEmbedded()) { + setReparented(false); + } + winAttr.isResizable = resizable; + if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { + fs &= ~(MWMConstants.MWM_FUNC_RESIZE + | MWMConstants.MWM_FUNC_MAXIMIZE); + } else { + fs |= (MWMConstants.MWM_FUNC_RESIZE + | MWMConstants.MWM_FUNC_MAXIMIZE); + } + winAttr.functions = fs; + XWM.setShellResizable(this); + } else if (isResizable() && !resizable) { + resetWMSetInsets(); + if (!isEmbedded()) { + setReparented(false); + } + winAttr.isResizable = resizable; + if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { + fs |= (MWMConstants.MWM_FUNC_RESIZE + | MWMConstants.MWM_FUNC_MAXIMIZE); + } else { + fs &= ~(MWMConstants.MWM_FUNC_RESIZE + | MWMConstants.MWM_FUNC_MAXIMIZE); + } + winAttr.functions = fs; + XWM.setShellNotResizable(this, dimensions, + XWM.getWMID() == XWM.UNITY_COMPIZ_WM && configure_seen ? + dimensions.getScreenBounds() : + dimensions.getBounds(), false); } - winAttr.functions = fs; - XWM.setShellResizable(this); - } else if (isResizable() && !resizable) { - resetWMSetInsets(); - if (!isEmbedded()) { - setReparented(false); - } - winAttr.isResizable = resizable; - if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { - fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); - } else { - fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); - } - winAttr.functions = fs; - XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false); + } finally { + XToolkit.awtUnlock(); } } @@ -990,17 +973,16 @@ try { if (configure_seen) { return toGlobal(0,0); - } else { - Point location = target.getLocation(); - if (insLog.isLoggable(PlatformLogger.Level.FINE)) { - insLog.fine("getLocationOnScreen {0} not reparented: {1} ", - this, location); - } - return location; } } finally { XToolkit.awtUnlock(); } + Point location = target.getLocation(); + if (insLog.isLoggable(PlatformLogger.Level.FINE)) { + insLog.fine("getLocationOnScreen {0} not reparented: {1} ", + this, location); + } + return location; } @@ -1134,7 +1116,7 @@ return focusProxy; } - public void handleQuit() { + private void handleQuit() { postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java Wed Jul 05 22:42:01 2017 +0200 @@ -1029,8 +1029,14 @@ } XToolkit.awtLock(); try { - Rectangle shellBounds = window.getShellBounds(); - shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); + Rectangle shellBounds; + if (getWMID() != UNITY_COMPIZ_WM) { + shellBounds = window.getShellBounds(); + shellBounds.translate(-window.currentInsets.left, + -window.currentInsets.top); + } else { + shellBounds = window.getDimensions().getScreenBounds(); + } window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java --- a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Wed Jul 05 22:42:01 2017 +0200 @@ -1053,15 +1053,8 @@ // of setting it, it is a safe assumption to just always // include SheetCollate as supported attribute. - /* - In Linux, we use Postscript for rendering but Linux still - has issues in propagating Postscript-embedded setpagedevice - setting like collation. Therefore, we temporarily exclude - Linux. - */ - if (!PrintServiceLookupProvider.isLinux()) { - catList.add(SheetCollate.class); - } + catList.add(SheetCollate.class); + } // With the assumption that Chromaticity is equivalent to diff -r 047a57b0839a -r 1c9922f121ff jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -362,59 +362,81 @@ } /** - * Main program to start a registry.
    - * The port number can be specified on the command line. + * Return a new RegistryImpl on the requested port and export it to serve + * registry requests. A classloader is initialized from the system property + * "env.class.path" and a security manager is set unless one is already set. + *

    + * The returned Registry is fully functional within the current process and + * is usable for internal and testing purposes. + * + * @param regPort port on which the rmiregistry accepts requests; + * if 0, an implementation specific port is assigned + * @return a RegistryImpl instance + * @exception RemoteException If remote operation failed. + * @since 9 */ - public static void main(String args[]) - { + public static RegistryImpl createRegistry(int regPort) throws RemoteException { // Create and install the security manager if one is not installed // already. if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } + /* + * Fix bugid 4147561: When JDK tools are executed, the value of + * the CLASSPATH environment variable for the shell in which they + * were invoked is no longer incorporated into the application + * class path; CLASSPATH's only effect is to be the value of the + * system property "env.class.path". To preserve the previous + * (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its + * CLASSPATH should still be considered when resolving classes + * being unmarshalled. To effect this old behavior, a class + * loader that loads from the file path specified in the + * "env.class.path" property is created and set to be the context + * class loader before the remote object is exported. + */ + String envcp = System.getProperty("env.class.path"); + if (envcp == null) { + envcp = "."; // preserve old default behavior + } + URL[] urls = pathToURLs(envcp); + ClassLoader cl = new URLClassLoader(urls); + + /* + * Fix bugid 4242317: Classes defined by this class loader should + * be annotated with the value of the "java.rmi.server.codebase" + * property, not the "file:" URLs for the CLASSPATH elements. + */ + sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl); + + Thread.currentThread().setContextClassLoader(cl); + + RegistryImpl registryImpl = null; try { - /* - * Fix bugid 4147561: When JDK tools are executed, the value of - * the CLASSPATH environment variable for the shell in which they - * were invoked is no longer incorporated into the application - * class path; CLASSPATH's only effect is to be the value of the - * system property "env.class.path". To preserve the previous - * (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its - * CLASSPATH should still be considered when resolving classes - * being unmarshalled. To effect this old behavior, a class - * loader that loads from the file path specified in the - * "env.class.path" property is created and set to be the context - * class loader before the remote object is exported. - */ - String envcp = System.getProperty("env.class.path"); - if (envcp == null) { - envcp = "."; // preserve old default behavior - } - URL[] urls = pathToURLs(envcp); - ClassLoader cl = new URLClassLoader(urls); + registryImpl = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public RegistryImpl run() throws RemoteException { + return new RegistryImpl(regPort); + } + }, getAccessControlContext(regPort)); + } catch (PrivilegedActionException ex) { + throw (RemoteException) ex.getException(); + } - /* - * Fix bugid 4242317: Classes defined by this class loader should - * be annotated with the value of the "java.rmi.server.codebase" - * property, not the "file:" URLs for the CLASSPATH elements. - */ - sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl); + return registryImpl; + } - Thread.currentThread().setContextClassLoader(cl); - + /** + * Main program to start a registry.
    + * The port number can be specified on the command line. + */ + public static void main(String args[]) + { + try { final int regPort = (args.length >= 1) ? Integer.parseInt(args[0]) : Registry.REGISTRY_PORT; - try { - registry = AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public RegistryImpl run() throws RemoteException { - return new RegistryImpl(regPort); - } - }, getAccessControlContext(regPort)); - } catch (PrivilegedActionException ex) { - throw (RemoteException) ex.getException(); - } + + registry = createRegistry(regPort); // prevent registry from exiting while (true) { diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp --- a/jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp Wed Jul 05 22:42:01 2017 +0200 @@ -102,26 +102,26 @@ JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalWidth (JNIEnv *, jobject) { - HANDLE hStdIn; - if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { + HANDLE hStdOut; + if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) { return -1; } CONSOLE_SCREEN_BUFFER_INFO info; - if (! GetConsoleScreenBufferInfo(hStdIn, &info)) { + if (! GetConsoleScreenBufferInfo(hStdOut, &info)) { return -1; } - return info.dwSize.X; + return info.srWindow.Right - info.srWindow.Left; } JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalHeight (JNIEnv *, jobject) { - HANDLE hStdIn; - if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { + HANDLE hStdOut; + if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) { return -1; } CONSOLE_SCREEN_BUFFER_INFO info; - if (! GetConsoleScreenBufferInfo(hStdIn, &info)) { + if (! GetConsoleScreenBufferInfo(hStdOut, &info)) { return -1; } - return info.dwSize.Y; + return info.srWindow.Bottom - info.srWindow.Top + 1; } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import java.nio.file.Paths; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; + +import jdk.internal.module.ModulePath; import jdk.internal.module.ModuleResolution; /** @@ -155,8 +157,8 @@ for (String dir : dirs) { paths[i++] = Paths.get(dir); } - jartool.moduleFinder = ModuleFinder.compose(jartool.moduleFinder, - ModuleFinder.of(paths)); + jartool.moduleFinder = + new ModulePath(Runtime.version(), true, paths); } }, new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") { @@ -169,9 +171,9 @@ new Option(true, OptionType.CREATE_UPDATE, "--warn-if-resolved") { void process(Main jartool, String opt, String arg) throws BadArgs { ModuleResolution mres = ModuleResolution.empty(); - if (jartool.moduleResolution.doNotResolveByDefault()) + if (jartool.moduleResolution.doNotResolveByDefault()) { mres.withDoNotResolveByDefault(); - + } if (arg.equals("deprecated")) { jartool.moduleResolution = mres.withDeprecated(); } else if (arg.equals("deprecated-for-removal")) { @@ -201,26 +203,27 @@ // Other options new Option(true, true, OptionType.OTHER, "--help", "-h") { void process(Main jartool, String opt, String arg) throws BadArgs { - if (arg == null) { - jartool.info = Main.Info.HELP; - return; + if (jartool.info == null) { + if (arg == null) { + jartool.info = GNUStyleOptions::printHelp; // Main.Info.HELP; + return; + } + if (!arg.equals("compat")) + throw new BadArgs("error.illegal.option", arg).showUsage(true); + // jartool.info = Main.Info.COMPAT_HELP; + jartool.info = GNUStyleOptions::printCompatHelp; } - - if (!arg.equals("compat")) - throw new BadArgs("error.illegal.option", arg).showUsage(true); - - jartool.info = Main.Info.COMPAT_HELP; } }, new Option(false, OptionType.OTHER, "--help-extra") { void process(Main jartool, String opt, String arg) throws BadArgs { - jartool.info = Main.Info.HELP_EXTRA; + jartool.info = GNUStyleOptions::printHelpExtra; } }, new Option(false, OptionType.OTHER, "--version") { void process(Main jartool, String opt, String arg) { if (jartool.info == null) - jartool.info = Main.Info.VERSION; + jartool.info = GNUStyleOptions::printVersion; } } }; @@ -279,14 +282,14 @@ static int parseOptions(Main jartool, String[] args) throws BadArgs { int count = 0; if (args.length == 0) { - jartool.info = Main.Info.USAGE_TRYHELP; + jartool.info = GNUStyleOptions::printUsageTryHelp; // never be here return 0; } // process options for (; count < args.length; count++) { - if (args[count].charAt(0) != '-' || args[count].equals("-C") - || args[count].equals("--release")) + if (args[count].charAt(0) != '-' || args[count].equals("-C") || + args[count].equals("--release")) break; String name = args[count]; @@ -322,15 +325,15 @@ throw new BadArgs("error.unrecognized.option", name).showUsage(true); } - static void printHelp(PrintWriter out) { - printHelp(out, false); + static void printHelpExtra(PrintWriter out) { + printHelp0(out, true); } - static void printHelpExtra(PrintWriter out) { - printHelp(out, true); + static void printHelp(PrintWriter out) { + printHelp0(out, false); } - private static void printHelp(PrintWriter out, boolean printExtra) { + private static void printHelp0(PrintWriter out, boolean printExtra) { out.format("%s%n", Main.getMsg("main.help.preopt")); for (OptionType type : OptionType.values()) { boolean typeHeadingWritten = false; diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.*; import java.lang.module.Configuration; +import java.lang.module.InvalidModuleDescriptorException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Provides; @@ -46,7 +47,7 @@ import java.nio.file.StandardCopyOption; import java.util.*; import java.util.function.Consumer; -import java.util.function.Function; +import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -58,6 +59,7 @@ import jdk.internal.module.Checks; import jdk.internal.module.ModuleHashes; +import jdk.internal.module.ModuleHashesBuilder; import jdk.internal.module.ModuleInfo; import jdk.internal.module.ModuleInfoExtender; import jdk.internal.module.ModuleResolution; @@ -66,7 +68,6 @@ import static jdk.internal.util.jar.JarIndex.INDEX_NAME; import static java.util.jar.JarFile.MANIFEST_NAME; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toSet; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; /** @@ -74,58 +75,24 @@ * (Java Archive) file format. The JAR format is based on the ZIP file * format, with optional meta-information stored in a MANIFEST entry. */ -public -class Main { +public class Main { String program; PrintWriter out, err; String fname, mname, ename; String zname = ""; String rootjar = null; - Set concealedPackages = new HashSet<>(); // used by Validator private static final int BASE_VERSION = 0; - class Entry { - final String basename; - final String entryname; + private static class Entry { + final String name; final File file; final boolean isDir; - Entry(File file, String basename, String entryname) { - this.file = file; - this.isDir = file.isDirectory(); - this.basename = basename; - this.entryname = entryname; - } - - Entry(int version, File file) { + Entry(File file, String name, boolean isDir) { this.file = file; - String path = file.getPath(); - if (file.isDirectory()) { - isDir = true; - path = path.endsWith(File.separator) ? path : - path + File.separator; - } else { - isDir = false; - } - EntryName en = new EntryName(path, version); - basename = en.baseName; - entryname = en.entryName; - } - - /** - * Returns a new Entry that trims the versions directory. - * - * This entry should be a valid entry matching the given version. - */ - Entry toVersionedEntry(int version) { - assert isValidVersionedEntry(this, version); - - if (version == BASE_VERSION) - return this; - - EntryName en = new EntryName(trimVersionsDir(basename, version), version); - return new Entry(this.file, en.baseName, en.entryName); + this.isDir = isDir; + this.name = name; } @Override @@ -141,32 +108,6 @@ } } - class EntryName { - final String baseName; - final String entryName; - - EntryName(String name, int version) { - name = name.replace(File.separatorChar, '/'); - String matchPath = ""; - for (String path : pathsMap.get(version)) { - if (name.startsWith(path) - && (path.length() > matchPath.length())) { - matchPath = path; - } - } - name = safeName(name.substring(matchPath.length())); - // the old implementaton doesn't remove - // "./" if it was led by "/" (?) - if (name.startsWith("./")) { - name = name.substring(2); - } - baseName = name; - entryName = (version > BASE_VERSION) - ? VERSIONS_DIR + version + "/" + baseName - : baseName; - } - } - // An entryName(path)->Entry map generated during "expand", it helps to // decide whether or not an existing entry in a jar file needs to be // replaced, during the "update" operation. @@ -175,11 +116,8 @@ // All entries need to be added/updated. Set entries = new LinkedHashSet<>(); - // All packages. - Set packages = new HashSet<>(); - // All actual entries added, or existing, in the jar file ( excl manifest - // and module-info.class ). Populated during create or update. - Set jarEntries = new HashSet<>(); + // module-info.class entries need to be added/updated. + Map moduleInfos = new HashMap<>(); // A paths Set for each version, where each Set contains directories // specified by the "-C" operation. @@ -208,19 +146,7 @@ boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag, dflag; /* To support additional GNU Style informational options */ - enum Info { - HELP(GNUStyleOptions::printHelp), - HELP_EXTRA(GNUStyleOptions::printHelpExtra), - COMPAT_HELP(GNUStyleOptions::printCompatHelp), - USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp), - VERSION(GNUStyleOptions::printVersion); - - private Consumer printFunction; - Info(Consumer f) { this.printFunction = f; } - void print(PrintWriter out) { printFunction.accept(out); } - }; - Info info; - + Consumer info; /* Modular jar related options */ Version moduleVersion; @@ -228,8 +154,7 @@ ModuleResolution moduleResolution = ModuleResolution.empty(); ModuleFinder moduleFinder = ModuleFinder.of(); - private static final String MODULE_INFO = "module-info.class"; - + static final String MODULE_INFO = "module-info.class"; static final String MANIFEST_DIR = "META-INF/"; static final String VERSIONS_DIR = MANIFEST_DIR + "versions/"; static final String VERSION = "1.0"; @@ -324,7 +249,6 @@ } } } - if (cflag) { Manifest manifest = null; if (!Mflag) { @@ -347,72 +271,60 @@ addMultiRelease(manifest); } } - - Map moduleInfoPaths = new HashMap<>(); - for (int version : filesMap.keySet()) { - String[] files = filesMap.get(version); - expand(null, files, false, moduleInfoPaths, version); - } - - Map moduleInfos = new LinkedHashMap<>(); - if (!moduleInfoPaths.isEmpty()) { - if (!checkModuleInfos(moduleInfoPaths)) - return false; - - // root module-info first - byte[] b = readModuleInfo(moduleInfoPaths.get(MODULE_INFO)); - moduleInfos.put(MODULE_INFO, b); - for (Map.Entry e : moduleInfoPaths.entrySet()) - moduleInfos.putIfAbsent(e.getKey(), readModuleInfo(e.getValue())); - - if (!addExtendedModuleAttributes(moduleInfos)) - return false; + expand(); + if (!moduleInfos.isEmpty()) { + // All actual file entries (excl manifest and module-info.class) + Set jentries = new HashSet<>(); + // all packages if it's a class or resource + Set packages = new HashSet<>(); + entries.stream() + .filter(e -> !e.isDir) + .forEach( e -> { + addPackageIfNamed(packages, e.name); + jentries.add(e.name); + }); + addExtendedModuleAttributes(moduleInfos, packages); // Basic consistency checks for modular jars. - if (!checkServices(moduleInfos.get(MODULE_INFO))) + if (!checkModuleInfo(moduleInfos.get(MODULE_INFO), jentries)) return false; } else if (moduleVersion != null || modulesToHash != null) { error(getMsg("error.module.options.without.info")); return false; } - if (vflag && fname == null) { // Disable verbose output so that it does not appear // on stdout along with file data // error("Warning: -v option ignored"); vflag = false; } - final String tmpbase = (fname == null) ? "tmpjar" : fname.substring(fname.indexOf(File.separatorChar) + 1); + File tmpfile = createTemporaryFile(tmpbase, ".jar"); - try (OutputStream out = new FileOutputStream(tmpfile)) { - create(new BufferedOutputStream(out, 4096), manifest, moduleInfos); + create(new BufferedOutputStream(out, 4096), manifest); } - if (nflag) { File packFile = createTemporaryFile(tmpbase, ".pack"); try { Packer packer = Pack200.newPacker(); Map p = packer.properties(); p.put(Packer.EFFORT, "1"); // Minimal effort to conserve CPU - try ( - JarFile jarFile = new JarFile(tmpfile.getCanonicalPath()); - OutputStream pack = new FileOutputStream(packFile) - ) { + try (JarFile jarFile = new JarFile(tmpfile.getCanonicalPath()); + OutputStream pack = new FileOutputStream(packFile)) + { packer.pack(jarFile, pack); } if (tmpfile.exists()) { tmpfile.delete(); } tmpfile = createTemporaryFile(tmpbase, ".jar"); - try ( - OutputStream out = new FileOutputStream(tmpfile); - JarOutputStream jos = new JarOutputStream(out) - ) { + try (OutputStream out = new FileOutputStream(tmpfile); + JarOutputStream jos = new JarOutputStream(out)) + { Unpacker unpacker = Pack200.newUnpacker(); unpacker.unpack(packFile, jos); } @@ -420,9 +332,7 @@ Files.deleteIfExists(packFile.toPath()); } } - validateAndClose(tmpfile); - } else if (uflag) { File inputFile = null, tmpFile = null; if (fname != null) { @@ -432,39 +342,20 @@ vflag = false; tmpFile = createTemporaryFile("tmpjar", ".jar"); } - - Map moduleInfoPaths = new HashMap<>(); - for (int version : filesMap.keySet()) { - String[] files = filesMap.get(version); - expand(null, files, true, moduleInfoPaths, version); + expand(); + try (FileInputStream in = (fname != null) ? new FileInputStream(inputFile) + : new FileInputStream(FileDescriptor.in); + FileOutputStream out = new FileOutputStream(tmpFile); + InputStream manifest = (!Mflag && (mname != null)) ? + (new FileInputStream(mname)) : null; + ) { + boolean updateOk = update(in, new BufferedOutputStream(out), + manifest, moduleInfos, null); + if (ok) { + ok = updateOk; + } } - - Map moduleInfos = new HashMap<>(); - for (Map.Entry e : moduleInfoPaths.entrySet()) - moduleInfos.put(e.getKey(), readModuleInfo(e.getValue())); - - try ( - FileInputStream in = (fname != null) ? new FileInputStream(inputFile) - : new FileInputStream(FileDescriptor.in); - FileOutputStream out = new FileOutputStream(tmpFile); - InputStream manifest = (!Mflag && (mname != null)) ? - (new FileInputStream(mname)) : null; - ) { - boolean updateOk = update(in, new BufferedOutputStream(out), - manifest, moduleInfos, null); - if (ok) { - ok = updateOk; - } - } - - // Consistency checks for modular jars. - if (!moduleInfos.isEmpty()) { - if(!checkServices(moduleInfos.get(MODULE_INFO))) - return false; - } - validateAndClose(tmpFile); - } else if (tflag) { replaceFSC(filesMap); // For the "list table contents" action, access using the @@ -542,12 +433,15 @@ private void validateAndClose(File tmpfile) throws IOException { if (ok && isMultiRelease) { - ok = validate(tmpfile.getCanonicalPath()); - if (!ok) { - error(formatMsg("error.validator.jarfile.invalid", fname)); + try (JarFile jf = new JarFile(tmpfile)) { + ok = Validator.validate(this, jf); + if (!ok) { + error(formatMsg("error.validator.jarfile.invalid", fname)); + } + } catch (IOException e) { + error(formatMsg2("error.validator.jarfile.exception", fname, e.getMessage())); } } - Path path = tmpfile.toPath(); try { if (ok) { @@ -572,78 +466,9 @@ Stream filesToEntryNames(Map.Entry fileEntries) { int version = fileEntries.getKey(); + Set cpaths = pathsMap.get(version); return Stream.of(fileEntries.getValue()) - .map(f -> (new EntryName(f, version)).entryName); - } - - // sort base entries before versioned entries, and sort entry classes with - // nested classes so that the top level class appears before the associated - // nested class - private Comparator entryComparator = (je1, je2) -> { - String s1 = je1.getName(); - String s2 = je2.getName(); - if (s1.equals(s2)) return 0; - boolean b1 = s1.startsWith(VERSIONS_DIR); - boolean b2 = s2.startsWith(VERSIONS_DIR); - if (b1 && !b2) return 1; - if (!b1 && b2) return -1; - int n = 0; // starting char for String compare - if (b1 && b2) { - // normally strings would be sorted so "10" goes before "9", but - // version number strings need to be sorted numerically - n = VERSIONS_DIR.length(); // skip the common prefix - int i1 = s1.indexOf('/', n); - int i2 = s1.indexOf('/', n); - if (i1 == -1) throw new InvalidJarException(s1); - if (i2 == -1) throw new InvalidJarException(s2); - // shorter version numbers go first - if (i1 != i2) return i1 - i2; - // otherwise, handle equal length numbers below - } - int l1 = s1.length(); - int l2 = s2.length(); - int lim = Math.min(l1, l2); - for (int k = n; k < lim; k++) { - char c1 = s1.charAt(k); - char c2 = s2.charAt(k); - if (c1 != c2) { - // change natural ordering so '.' comes before '$' - // i.e. top level classes come before nested classes - if (c1 == '$' && c2 == '.') return 1; - if (c1 == '.' && c2 == '$') return -1; - return c1 - c2; - } - } - return l1 - l2; - }; - - private boolean validate(String fname) { - boolean valid; - - try (JarFile jf = new JarFile(fname)) { - Validator validator = new Validator(this, jf); - jf.stream() - .filter(e -> !e.isDirectory()) - .filter(e -> !e.getName().equals(MANIFEST_NAME)) - .filter(e -> !e.getName().endsWith(MODULE_INFO)) - .sorted(entryComparator) - .forEachOrdered(validator); - valid = validator.isValid(); - } catch (IOException e) { - error(formatMsg2("error.validator.jarfile.exception", fname, e.getMessage())); - valid = false; - } catch (InvalidJarException e) { - error(formatMsg("error.validator.bad.entry.name", e.getMessage())); - valid = false; - } - return valid; - } - - private static class InvalidJarException extends RuntimeException { - private static final long serialVersionUID = -3642329147299217726L; - InvalidJarException(String msg) { - super(msg); - } + .map(f -> toVersionedName(toEntryName(f, cpaths, false), version)); } /** @@ -668,20 +493,22 @@ // Note: flags.length == 2 can be treated as the short version of // the GNU option since the there cannot be any other options, // excluding -C, as per the old way. - if (flags.startsWith("--") - || (flags.startsWith("-") && flags.length() == 2)) { + if (flags.startsWith("--") || + (flags.startsWith("-") && flags.length() == 2)) { try { count = GNUStyleOptions.parseOptions(this, args); } catch (GNUStyleOptions.BadArgs x) { if (info == null) { - error(x.getMessage()); - if (x.showUsage) - Info.USAGE_TRYHELP.print(err); + if (x.showUsage) { + usageError(x.getMessage()); + } else { + error(x.getMessage()); + } return false; } } if (info != null) { - info.print(out); + info.accept(out); return true; } } else { @@ -851,19 +678,55 @@ * Add the package of the given resource name if it's a .class * or a resource in a named package. */ - boolean addPackageIfNamed(String name) { + void addPackageIfNamed(Set packages, String name) { if (name.startsWith(VERSIONS_DIR)) { - throw new InternalError(name); + // trim the version dir prefix + int i0 = VERSIONS_DIR.length(); + int i = name.indexOf('/', i0); + if (i <= 0) { + warn(formatMsg("warn.release.unexpected.versioned.entry", name)); + return; + } + while (i0 < i) { + char c = name.charAt(i0); + if (c < '0' || c > '9') { + warn(formatMsg("warn.release.unexpected.versioned.entry", name)); + return; + } + i0++; + } + name = name.substring(i + 1, name.length()); } - String pn = toPackageName(name); // add if this is a class or resource in a package if (Checks.isJavaIdentifier(pn)) { packages.add(pn); - return true; + } + } + + private String toEntryName(String name, Set cpaths, boolean isDir) { + name = name.replace(File.separatorChar, '/'); + if (isDir) { + name = name.endsWith("/") ? name : name + "/"; } + String matchPath = ""; + for (String path : cpaths) { + if (name.startsWith(path) && path.length() > matchPath.length()) { + matchPath = path; + } + } + name = safeName(name.substring(matchPath.length())); + // the old implementaton doesn't remove + // "./" if it was led by "/" (?) + if (name.startsWith("./")) { + name = name.substring(2); + } + return name; + } - return false; + private static String toVersionedName(String name, int version) { + return version > BASE_VERSION + ? VERSIONS_DIR + version + "/" + name : name; } private static String toPackageName(String path) { @@ -875,57 +738,23 @@ } } - /* - * Returns true if the given entry is a valid entry of the given version. - */ - private boolean isValidVersionedEntry(Entry entry, int version) { - String name = entry.basename; - if (name.startsWith(VERSIONS_DIR) && version != BASE_VERSION) { - int i = name.indexOf('/', VERSIONS_DIR.length()); - // name == -1 -> not a versioned directory, something else - if (i == -1) - return false; - try { - String v = name.substring(VERSIONS_DIR.length(), i); - return Integer.valueOf(v) == version; - } catch (NumberFormatException x) { - return false; - } + private void expand() throws IOException { + for (int version : filesMap.keySet()) { + String[] files = filesMap.get(version); + expand(null, files, pathsMap.get(version), version); } - return true; - } - - /* - * Trim META-INF/versions/$version/ from the given name if the - * given name is a versioned entry of the given version; or - * of any version if the given version is BASE_VERSION - */ - private String trimVersionsDir(String name, int version) { - if (name.startsWith(VERSIONS_DIR)) { - int i = name.indexOf('/', VERSIONS_DIR.length()); - if (i >= 0) { - try { - String v = name.substring(VERSIONS_DIR.length(), i); - if (version == BASE_VERSION || Integer.valueOf(v) == version) { - return name.substring(i + 1, name.length()); - } - } catch (NumberFormatException x) {} - } - throw new InternalError("unexpected versioned entry: " + - name + " version " + version); - } - return name; } /** * Expands list of files to process into full list of all files that * can be found by recursively descending directories. + * + * @param dir parent directory + * @param file s list of files to expand + * @param cpaths set of directories specified by -C option for the files + * @throws IOException if an I/O error occurs */ - void expand(File dir, - String[] files, - boolean isUpdate, - Map moduleInfoPaths, - int version) + private void expand(File dir, String[] files, Set cpaths, int version) throws IOException { if (files == null) @@ -938,47 +767,48 @@ else f = new File(dir, files[i]); - Entry e = new Entry(version, f); - String entryName = e.entryname; - Entry entry = e; - if (e.basename.startsWith(VERSIONS_DIR) && isValidVersionedEntry(e, version)) { - entry = e.toVersionedEntry(version); - } - if (f.isFile()) { - if (entryName.endsWith(MODULE_INFO)) { - moduleInfoPaths.put(entryName, f.toPath()); - if (isUpdate) - entryMap.put(entryName, entry); - } else if (isValidVersionedEntry(entry, version)) { - if (entries.add(entry)) { - jarEntries.add(entryName); - // add the package if it's a class or resource - addPackageIfNamed(trimVersionsDir(entry.basename, version)); - if (isUpdate) - entryMap.put(entryName, entry); - } - } else { + boolean isDir = f.isDirectory(); + String name = toEntryName(f.getPath(), cpaths, isDir); + + if (version != BASE_VERSION) { + if (name.startsWith(VERSIONS_DIR)) { + // the entry starts with VERSIONS_DIR and version != BASE_VERSION, + // which means the "[dirs|files]" in --release v [dirs|files] + // includes VERSIONS_DIR-ed entries --> warning and skip (?) error(formatMsg2("error.release.unexpected.versioned.entry", - entry.basename, String.valueOf(version))); + name, String.valueOf(version))); ok = false; + return; } - } else if (f.isDirectory()) { - if (isValidVersionedEntry(entry, version)) { - if (entries.add(entry)) { - if (isUpdate) { - entryMap.put(entryName, entry); - } + name = toVersionedName(name, version); + } + + if (f.isFile()) { + Entry e = new Entry(f, name, false); + if (isModuleInfoEntry(name)) { + moduleInfos.putIfAbsent(name, Files.readAllBytes(f.toPath())); + if (uflag) + entryMap.put(name, e); + } else if (entries.add(e)) { + if (uflag) + entryMap.put(name, e); + } + } else if (isDir) { + Entry e = new Entry(f, name, true); + if (entries.add(e)) { + // utilize entryMap for the duplicate dir check even in + // case of cflag == true. + // dir name confilict/duplicate could happen with -C option. + // just remove the last "e" from the "entries" (zos will fail + // with "duplicated" entries), but continue expanding the + // sub tree + if (entryMap.containsKey(name)) { + entries.remove(e); + } else { + entryMap.put(name, e); } - } else if (entry.basename.equals(VERSIONS_DIR)) { - if (vflag) { - output(formatMsg("out.ignore.entry", entry.basename)); - } - } else { - error(formatMsg2("error.release.unexpected.versioned.entry", - entry.basename, String.valueOf(version))); - ok = false; + expand(f, f.list(), cpaths, version); } - expand(f, f.list(), isUpdate, moduleInfoPaths, version); } else { error(formatMsg("error.nosuch.fileordir", String.valueOf(f))); ok = false; @@ -989,52 +819,36 @@ /** * Creates a new JAR file. */ - void create(OutputStream out, Manifest manifest, Map moduleInfos) - throws IOException + void create(OutputStream out, Manifest manifest) throws IOException { - ZipOutputStream zos = new JarOutputStream(out); - if (flag0) { - zos.setMethod(ZipOutputStream.STORED); - } - // TODO: check module-info attributes against manifest ?? - if (manifest != null) { - if (vflag) { - output(getMsg("out.added.manifest")); - } - ZipEntry e = new ZipEntry(MANIFEST_DIR); - e.setTime(System.currentTimeMillis()); - e.setSize(0); - e.setCrc(0); - zos.putNextEntry(e); - e = new ZipEntry(MANIFEST_NAME); - e.setTime(System.currentTimeMillis()); + try (ZipOutputStream zos = new JarOutputStream(out)) { if (flag0) { - crc32Manifest(e, manifest); + zos.setMethod(ZipOutputStream.STORED); } - zos.putNextEntry(e); - manifest.write(zos); - zos.closeEntry(); - } - for (Map.Entry mi : moduleInfos.entrySet()) { - String entryName = mi.getKey(); - byte[] miBytes = mi.getValue(); - if (vflag) { - output(formatMsg("out.added.module-info", entryName)); + // TODO: check module-info attributes against manifest ?? + if (manifest != null) { + if (vflag) { + output(getMsg("out.added.manifest")); + } + ZipEntry e = new ZipEntry(MANIFEST_DIR); + e.setTime(System.currentTimeMillis()); + e.setSize(0); + e.setCrc(0); + zos.putNextEntry(e); + e = new ZipEntry(MANIFEST_NAME); + e.setTime(System.currentTimeMillis()); + if (flag0) { + crc32Manifest(e, manifest); + } + zos.putNextEntry(e); + manifest.write(zos); + zos.closeEntry(); } - ZipEntry e = new ZipEntry(mi.getKey()); - e.setTime(System.currentTimeMillis()); - if (flag0) { - crc32ModuleInfo(e, miBytes); + updateModuleInfo(moduleInfos, zos); + for (Entry entry : entries) { + addFile(zos, entry); } - zos.putNextEntry(e); - ByteArrayInputStream in = new ByteArrayInputStream(miBytes); - in.transferTo(zos); - zos.closeEntry(); } - for (Entry entry : entries) { - addFile(zos, entry); - } - zos.close(); } private char toUpperCaseASCII(char c) { @@ -1062,30 +876,6 @@ } /** - * Returns true of the given module-info's are located in acceptable - * locations. Otherwise, outputs an appropriate message and returns false. - */ - private boolean checkModuleInfos(Map moduleInfos) { - // there must always be, at least, a root module-info - if (!moduleInfos.containsKey(MODULE_INFO)) { - error(getMsg("error.versioned.info.without.root")); - return false; - } - - // module-info can only appear in the root, or a versioned section - Optional other = moduleInfos.keySet().stream() - .filter(x -> !x.equals(MODULE_INFO)) - .filter(x -> !x.startsWith(VERSIONS_DIR)) - .findFirst(); - - if (other.isPresent()) { - error(formatMsg("error.unexpected.module-info", other.get())); - return false; - } - return true; - } - - /** * Updates an existing jar file. */ boolean update(InputStream in, OutputStream out, @@ -1099,6 +889,10 @@ boolean foundManifest = false; boolean updateOk = true; + // All actual entries added/updated/existing, in the jar file (excl manifest + // and module-info.class ). + Set jentries = new HashSet<>(); + if (jarIndex != null) { addIndex(jarIndex, zos); } @@ -1108,7 +902,7 @@ String name = e.getName(); boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME); - boolean isModuleInfoEntry = name.endsWith(MODULE_INFO); + boolean isModuleInfoEntry = isModuleInfoEntry(name); if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME)) || (Mflag && isManifestEntry)) { @@ -1127,7 +921,6 @@ return false; } } - // Update the manifest. Manifest old = new Manifest(zis); if (newManifest != null) { @@ -1137,7 +930,7 @@ return false; } } else if (moduleInfos != null && isModuleInfoEntry) { - moduleInfos.putIfAbsent(name, readModuleInfo(zis)); + moduleInfos.putIfAbsent(name, zis.readAllBytes()); } else { boolean isDir = e.isDirectory(); if (!entryMap.containsKey(name)) { // copy the old stuff @@ -1160,11 +953,8 @@ entries.remove(ent); isDir = ent.isDir; } - - jarEntries.add(name); if (!isDir) { - // add the package if it's a class or resource - addPackageIfNamed(trimVersionsDir(name, BASE_VERSION)); + jentries.add(name); } } } @@ -1172,6 +962,9 @@ // add the remaining new files for (Entry entry : entries) { addFile(zos, entry); + if (!entry.isDir) { + jentries.add(entry.name); + } } if (!foundManifest) { if (newManifest != null) { @@ -1188,35 +981,24 @@ } } } - - if (moduleInfos != null && !moduleInfos.isEmpty()) { - if (!checkModuleInfos(moduleInfos)) + if (updateOk) { + if (moduleInfos != null && !moduleInfos.isEmpty()) { + Set pkgs = new HashSet<>(); + jentries.forEach( je -> addPackageIfNamed(pkgs, je)); + addExtendedModuleAttributes(moduleInfos, pkgs); + updateOk = checkModuleInfo(moduleInfos.get(MODULE_INFO), jentries); + updateModuleInfo(moduleInfos, zos); + // TODO: check manifest main classes, etc + } else if (moduleVersion != null || modulesToHash != null) { + error(getMsg("error.module.options.without.info")); updateOk = false; - - if (updateOk) { - if (!addExtendedModuleAttributes(moduleInfos)) - updateOk = false; } - - // TODO: check manifest main classes, etc - - if (updateOk) { - for (Map.Entry mi : moduleInfos.entrySet()) { - if (!updateModuleInfo(mi.getValue(), zos, mi.getKey())) - updateOk = false; - } - } - } else if (moduleVersion != null || modulesToHash != null) { - error(getMsg("error.module.options.without.info")); - updateOk = false; } - zis.close(); zos.close(); return updateOk; } - private void addIndex(JarIndex index, ZipOutputStream zos) throws IOException { @@ -1232,20 +1014,25 @@ zos.closeEntry(); } - private boolean updateModuleInfo(byte[] moduleInfoBytes, ZipOutputStream zos, String entryName) + private void updateModuleInfo(Map moduleInfos, ZipOutputStream zos) throws IOException { - ZipEntry e = new ZipEntry(entryName); - e.setTime(System.currentTimeMillis()); - if (flag0) { - crc32ModuleInfo(e, moduleInfoBytes); + String fmt = uflag ? "out.update.module-info": "out.added.module-info"; + for (Map.Entry mi : moduleInfos.entrySet()) { + String name = mi.getKey(); + byte[] bytes = mi.getValue(); + ZipEntry e = new ZipEntry(name); + e.setTime(System.currentTimeMillis()); + if (flag0) { + crc32ModuleInfo(e, bytes); + } + zos.putNextEntry(e); + zos.write(bytes); + zos.closeEntry(); + if (vflag) { + output(formatMsg(fmt, name)); + } } - zos.putNextEntry(e); - zos.write(moduleInfoBytes); - if (vflag) { - output(formatMsg("out.update.module-info", entryName)); - } - return true; } private boolean updateManifest(Manifest m, ZipOutputStream zos) @@ -1358,11 +1145,9 @@ * Adds a new file entry to the ZIP output stream. */ void addFile(ZipOutputStream zos, Entry entry) throws IOException { - // skip the generation of directory entries for META-INF/versions/*/ - if (entry.basename.isEmpty()) return; File file = entry.file; - String name = entry.entryname; + String name = entry.name; boolean isDir = entry.isDir; if (name.equals("") || name.equals(".") || name.equals(zname)) { @@ -1444,11 +1229,8 @@ * @throws IOException if an I/O error occurs */ private void copy(File from, OutputStream to) throws IOException { - InputStream in = new FileInputStream(from); - try { + try (InputStream in = new FileInputStream(from)) { copy(in, to); - } finally { - in.close(); } } @@ -1461,11 +1243,8 @@ * @throws IOException if an I/O error occurs */ private void copy(InputStream from, File to) throws IOException { - OutputStream out = new FileOutputStream(to); - try { + try (OutputStream out = new FileOutputStream(to)) { copy(from, out); - } finally { - out.close(); } } @@ -1825,7 +1604,7 @@ */ void usageError(String s) { err.println(s); - Info.USAGE_TRYHELP.print(err); + err.println(getMsg("main.usage.summary.try")); } /** @@ -1934,16 +1713,6 @@ return tmpfile; } - private static byte[] readModuleInfo(InputStream zis) throws IOException { - return zis.readAllBytes(); - } - - private static byte[] readModuleInfo(Path path) throws IOException { - try (InputStream is = Files.newInputStream(path)) { - return is.readAllBytes(); - } - } - // Modular jar support static String toString(Collection c, @@ -1951,7 +1720,6 @@ CharSequence suffix ) { if (c.isEmpty()) return ""; - return c.stream().map(e -> e.toString()) .collect(joining(", ", prefix, suffix)); } @@ -2045,136 +1813,84 @@ md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v)); - if (hashes != null) { - hashes.names().stream().sorted().forEach( - mod -> sb.append("\n hashes ").append(mod).append(" ") - .append(hashes.algorithm()).append(" ") - .append(toHex(hashes.hashFor(mod)))); + if (hashes != null) { + hashes.names().stream().sorted().forEach( + mod -> sb.append("\n hashes ").append(mod).append(" ") + .append(hashes.algorithm()).append(" ") + .append(toHex(hashes.hashFor(mod)))); } output(sb.toString()); } private static String toHex(byte[] ba) { - StringBuilder sb = new StringBuilder(ba.length); + StringBuilder sb = new StringBuilder(ba.length << 1); for (byte b: ba) { sb.append(String.format("%02x", b & 0xff)); } return sb.toString(); } - private static String toBinaryName(String classname) { + static String toBinaryName(String classname) { return (classname.replace('.', '/')) + ".class"; } - /* A module must have the implementation class of the services it 'provides'. */ - private boolean checkServices(byte[] moduleInfoBytes) + private boolean checkModuleInfo(byte[] moduleInfoBytes, Set entries) throws IOException { - ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes)); - Set missing = md.provides() - .stream() - .map(Provides::providers) - .flatMap(List::stream) - .filter(p -> !jarEntries.contains(toBinaryName(p))) - .collect(Collectors.toSet()); - if (missing.size() > 0) { - missing.stream().forEach(s -> fatalError(formatMsg("error.missing.provider", s))); - return false; + boolean ok = true; + if (moduleInfoBytes != null) { // no root module-info.class if null + try { + // ModuleDescriptor.read() checks open/exported pkgs vs packages + ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes)); + // A module must have the implementation class of the services it 'provides'. + if (md.provides().stream().map(Provides::providers).flatMap(List::stream) + .filter(p -> !entries.contains(toBinaryName(p))) + .peek(p -> fatalError(formatMsg("error.missing.provider", p))) + .count() != 0) { + ok = false; + } + } catch (InvalidModuleDescriptorException x) { + fatalError(x.getMessage()); + ok = false; + } } - return true; + return ok; } /** * Adds extended modules attributes to the given module-info's. The given * Map values are updated in-place. Returns false if an error occurs. */ - private boolean addExtendedModuleAttributes(Map moduleInfos) + private void addExtendedModuleAttributes(Map moduleInfos, + Set packages) throws IOException { - assert !moduleInfos.isEmpty() && moduleInfos.get(MODULE_INFO) != null; - - ByteBuffer bb = ByteBuffer.wrap(moduleInfos.get(MODULE_INFO)); - ModuleDescriptor rd = ModuleDescriptor.read(bb); - - 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(), packages)); + ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue())); + e.setValue(extendedInfoBytes(md, e.getValue(), packages)); } - return true; - } - - private Set findConcealedPackages(ModuleDescriptor md) { - Objects.requireNonNull(md); - Set concealed = new HashSet<>(packages); - md.exports().stream().map(Exports::source).forEach(concealed::remove); - md.opens().stream().map(Opens::source).forEach(concealed::remove); - return concealed; - } - - private static boolean isPlatformModule(String name) { - return name.startsWith("java.") || name.startsWith("jdk."); } - /** - * Tells whether or not the given versioned module descriptor's attributes - * are valid when compared against the given root module descriptor. - * - * A versioned module descriptor must be identical to the root module - * descriptor, with two exceptions: - * - A versioned descriptor can have different non-public `requires` - * clauses of platform ( `java.*` and `jdk.*` ) modules, and - * - A versioned descriptor can have different `uses` clauses, even of - * service types defined outside of the platform modules. - */ - private boolean isValidVersionedDescriptor(ModuleDescriptor vd, - ModuleDescriptor rd) - throws IOException - { - if (!rd.name().equals(vd.name())) { - fatalError(getMsg("error.versioned.info.name.notequal")); - return false; - } - if (!rd.requires().equals(vd.requires())) { - Set rootRequires = rd.requires(); - for (Requires r : vd.requires()) { - if (rootRequires.contains(r)) { - continue; - } else if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) { - fatalError(getMsg("error.versioned.info.requires.transitive")); + static boolean isModuleInfoEntry(String name) { + // root or versioned module-info.class + if (name.endsWith(MODULE_INFO)) { + int end = name.length() - MODULE_INFO.length(); + if (end == 0) + return true; + if (name.startsWith(VERSIONS_DIR)) { + int off = VERSIONS_DIR.length(); + if (off == end) // meta-inf/versions/module-info.class return false; - } else if (!isPlatformModule(r.name())) { - fatalError(getMsg("error.versioned.info.requires.added")); - return false; + while (off < end - 1) { + char c = name.charAt(off++); + if (c < '0' || c > '9') + return false; } - } - for (Requires r : rootRequires) { - Set mdRequires = vd.requires(); - if (mdRequires.contains(r)) { - continue; - } else if (!isPlatformModule(r.name())) { - fatalError(getMsg("error.versioned.info.requires.dropped")); - return false; - } + return name.charAt(off) == '/'; } } - if (!rd.exports().equals(vd.exports())) { - fatalError(getMsg("error.versioned.info.exports.notequal")); - return false; - } - if (!rd.opens().equals(vd.opens())) { - fatalError(getMsg("error.versioned.info.opens.notequal")); - return false; - } - if (!rd.provides().equals(vd.provides())) { - fatalError(getMsg("error.versioned.info.provides.notequal")); - return false; - } - return true; + return false; } /** @@ -2185,8 +1901,7 @@ * then the corresponding class file attributes are added to the * module-info here. */ - private byte[] extendedInfoBytes(ModuleDescriptor rootDescriptor, - ModuleDescriptor md, + private byte[] extendedInfoBytes(ModuleDescriptor md, byte[] miBytes, Set packages) throws IOException @@ -2201,14 +1916,10 @@ // --main-class if (ename != null) extender.mainClass(ename); - else if (rootDescriptor.mainClass().isPresent()) - extender.mainClass(rootDescriptor.mainClass().get()); // --module-version if (moduleVersion != null) extender.version(moduleVersion); - else if (rootDescriptor.version().isPresent()) - extender.version(rootDescriptor.version().get()); // --hash-modules if (modulesToHash != null) { @@ -2218,8 +1929,7 @@ if (moduleHashes != null) { extender.hashes(moduleHashes); } else { - // should it issue warning or silent? - System.out.println("warning: no module is recorded in hash in " + mn); + warn("warning: no module is recorded in hash in " + mn); } } @@ -2235,10 +1945,9 @@ * Compute and record hashes */ private class Hasher { + final ModuleHashesBuilder hashesBuilder; final ModuleFinder finder; - final Map moduleNameToPath; final Set modules; - final Configuration configuration; Hasher(ModuleDescriptor descriptor, String fname) throws IOException { // Create a module finder that finds the modular JAR // being created/updated @@ -2268,119 +1977,46 @@ } }); - // Determine the modules that matches the modulesToHash pattern - this.modules = moduleFinder.findAll().stream() - .map(moduleReference -> moduleReference.descriptor().name()) + // Determine the modules that matches the pattern {@code modulesToHash} + Set roots = finder.findAll().stream() + .map(ref -> ref.descriptor().name()) .filter(mn -> modulesToHash.matcher(mn).find()) .collect(Collectors.toSet()); - // a map from a module name to Path of the modular JAR - this.moduleNameToPath = moduleFinder.findAll().stream() - .map(ModuleReference::descriptor) - .map(ModuleDescriptor::name) - .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn))); - - Configuration config = null; - try { - config = Configuration.empty() - .resolveRequires(ModuleFinder.ofSystem(), finder, modules); - } catch (ResolutionException e) { - // should it throw an error? or emit a warning - System.out.println("warning: " + e.getMessage()); + // use system module path unless it creates a modular JAR for + // a module that is present in the system image e.g. upgradeable + // module + ModuleFinder system; + String name = descriptor.name(); + if (name != null && ModuleFinder.ofSystem().find(name).isPresent()) { + system = ModuleFinder.of(); + } else { + system = ModuleFinder.ofSystem(); } - this.configuration = config; - } + // get a resolved module graph + Configuration config = + Configuration.empty().resolveRequires(system, finder, roots); - /** - * Compute hashes of the modules that depend upon the specified - * module directly or indirectly. - */ - ModuleHashes computeHashes(String name) { - // the transposed graph includes all modules in the resolved graph - Map> graph = transpose(); + // filter modules resolved from the system module finder + this.modules = config.modules().stream() + .map(ResolvedModule::name) + .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent()) + .collect(Collectors.toSet()); - // find the modules that transitively depend upon the specified name - Deque deque = new ArrayDeque<>(); - deque.add(name); - Set mods = visitNodes(graph, deque); - - // filter modules matching the pattern specified in --hash-modules, - // as well as the modular jar file that is being created / updated - Map modulesForHash = mods.stream() - .filter(mn -> !mn.equals(name) && modules.contains(mn)) - .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get)); - - if (modulesForHash.isEmpty()) - return null; - - return ModuleHashes.generate(modulesForHash, "SHA-256"); + this.hashesBuilder = new ModuleHashesBuilder(config, modules); } /** - * Returns all nodes traversed from the given roots. + * Compute hashes of the specified module. + * + * It records the hashing modules that depend upon the specified + * module directly or indirectly. */ - private Set visitNodes(Map> graph, - Deque roots) { - Set visited = new HashSet<>(); - while (!roots.isEmpty()) { - String mn = roots.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - - // the given roots may not be part of the graph - if (graph.containsKey(mn)) { - for (String dm : graph.get(mn)) { - if (!visited.contains(dm)) - roots.push(dm); - } - } - } - } - return visited; - } - - /** - * Returns a transposed graph from the resolved module graph. - */ - private Map> transpose() { - Map> transposedGraph = new HashMap<>(); - Deque deque = new ArrayDeque<>(modules); + ModuleHashes computeHashes(String name) { + if (hashesBuilder == null) + return null; - Set visited = new HashSet<>(); - while (!deque.isEmpty()) { - String mn = deque.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - - // add an empty set - transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>()); - - ResolvedModule resolvedModule = configuration.findModule(mn).get(); - for (ResolvedModule dm : resolvedModule.reads()) { - String name = dm.name(); - if (!visited.contains(name)) { - deque.push(name); - } - // reverse edge - transposedGraph.computeIfAbsent(name, _k -> new HashSet<>()) - .add(mn); - } - } - } - return transposedGraph; - } - - private Path moduleToPath(String name) { - ModuleReference mref = moduleFinder.find(name).orElseThrow( - () -> new InternalError(formatMsg2("error.hash.dep",name , name))); - - URI uri = mref.location().get(); - Path path = Paths.get(uri); - String fn = path.getFileName().toString(); - if (!fn.endsWith(".jar")) { - throw new UnsupportedOperationException(path + " is not a modular JAR"); - } - return path; + return hashesBuilder.computeHashes(Set.of(name)).get(name); } } } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * 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,32 +25,120 @@ package sun.tools.jar; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor.Opens; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Requires; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.zip.ZipEntry; -final class Validator implements Consumer { +import static java.util.jar.JarFile.MANIFEST_NAME; +import static sun.tools.jar.Main.VERSIONS_DIR; +import static sun.tools.jar.Main.MODULE_INFO; +import static sun.tools.jar.Main.getMsg; +import static sun.tools.jar.Main.formatMsg; +import static sun.tools.jar.Main.formatMsg2; +import static sun.tools.jar.Main.toBinaryName; +import static sun.tools.jar.Main.isModuleInfoEntry; + +final class Validator { private final static boolean DEBUG = Boolean.getBoolean("jar.debug"); private final Map fps = new HashMap<>(); - private final int vdlen = Main.VERSIONS_DIR.length(); + private static final int vdlen = VERSIONS_DIR.length(); private final Main main; private final JarFile jf; private int oldVersion = -1; private String currentTopLevelName; private boolean isValid = true; + private Set concealedPkgs; + private ModuleDescriptor md; - Validator(Main main, JarFile jf) { + private Validator(Main main, JarFile jf) { this.main = main; this.jf = jf; + loadModuleDescriptor(); + } + + static boolean validate(Main main, JarFile jf) throws IOException { + return new Validator(main, jf).validate(); + } + + private boolean validate() { + try { + jf.stream() + .filter(e -> !e.isDirectory() && + !e.getName().equals(MANIFEST_NAME)) + .sorted(entryComparator) + .forEachOrdered(e -> validate(e)); + return isValid; + } catch (InvalidJarException e) { + error(formatMsg("error.validator.bad.entry.name", e.getMessage())); + } + return false; + } + + private static class InvalidJarException extends RuntimeException { + private static final long serialVersionUID = -3642329147299217726L; + InvalidJarException(String msg) { + super(msg); + } } - boolean isValid() { - return isValid; - } + // sort base entries before versioned entries, and sort entry classes with + // nested classes so that the top level class appears before the associated + // nested class + private static Comparator entryComparator = (je1, je2) -> { + String s1 = je1.getName(); + String s2 = je2.getName(); + if (s1.equals(s2)) return 0; + boolean b1 = s1.startsWith(VERSIONS_DIR); + boolean b2 = s2.startsWith(VERSIONS_DIR); + if (b1 && !b2) return 1; + if (!b1 && b2) return -1; + int n = 0; // starting char for String compare + if (b1 && b2) { + // normally strings would be sorted so "10" goes before "9", but + // version number strings need to be sorted numerically + n = VERSIONS_DIR.length(); // skip the common prefix + int i1 = s1.indexOf('/', n); + int i2 = s1.indexOf('/', n); + if (i1 == -1) throw new InvalidJarException(s1); + if (i2 == -1) throw new InvalidJarException(s2); + // shorter version numbers go first + if (i1 != i2) return i1 - i2; + // otherwise, handle equal length numbers below + } + int l1 = s1.length(); + int l2 = s2.length(); + int lim = Math.min(l1, l2); + for (int k = n; k < lim; k++) { + char c1 = s1.charAt(k); + char c2 = s2.charAt(k); + if (c1 != c2) { + // change natural ordering so '.' comes before '$' + // i.e. top level classes come before nested classes + if (c1 == '$' && c2 == '.') return 1; + if (c1 == '.' && c2 == '$') return -1; + return c1 - c2; + } + } + return l1 - l2; + }; /* * Validator has state and assumes entries provided to accept are ordered @@ -59,7 +147,7 @@ * classes must be ordered so that the top level class is before the associated * nested class(es). */ - public void accept(JarEntry je) { + public void validate(JarEntry je) { String entryName = je.getName(); // directories are always accepted @@ -68,13 +156,20 @@ return; } + // validate the versioned module-info + if (isModuleInfoEntry(entryName)) { + if (entryName.length() != MODULE_INFO.length()) + checkModuleDescriptor(je); + return; + } + // figure out the version and basename from the JarEntry int version; String basename; - if (entryName.startsWith(Main.VERSIONS_DIR)) { + if (entryName.startsWith(VERSIONS_DIR)) { int n = entryName.indexOf("/", vdlen); if (n == -1) { - main.error(Main.formatMsg("error.validator.version.notnumber", entryName)); + error(formatMsg("error.validator.version.notnumber", entryName)); isValid = false; return; } @@ -82,12 +177,12 @@ try { version = Integer.parseInt(v); } catch (NumberFormatException x) { - main.error(Main.formatMsg("error.validator.version.notnumber", entryName)); + error(formatMsg("error.validator.version.notnumber", entryName)); isValid = false; return; } if (n == entryName.length()) { - main.error(Main.formatMsg("error.validator.entryname.tooshort", entryName)); + error(formatMsg("error.validator.entryname.tooshort", entryName)); isValid = false; return; } @@ -108,7 +203,7 @@ try (InputStream is = jf.getInputStream(je)) { fp = new FingerPrint(basename, is.readAllBytes()); } catch (IOException x) { - main.error(x.getMessage()); + error(x.getMessage()); isValid = false; return; } @@ -123,7 +218,7 @@ fps.put(internalName, fp); return; } - main.error(Main.formatMsg("error.validator.isolated.nested.class", entryName)); + error(formatMsg("error.validator.isolated.nested.class", entryName)); isValid = false; return; } @@ -153,11 +248,11 @@ } if (fp.isPublicClass()) { if (!isConcealed(internalName)) { - main.error(Main.formatMsg("error.validator.new.public.class", entryName)); + error(Main.formatMsg("error.validator.new.public.class", entryName)); isValid = false; return; } - main.warn(Main.formatMsg("warn.validator.concealed.public.class", entryName)); + warn(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); @@ -173,7 +268,7 @@ // are the two classes/resources identical? if (fp.isIdentical(matchFp)) { - main.warn(Main.formatMsg("warn.validator.identical.entry", entryName)); + warn(formatMsg("warn.validator.identical.entry", entryName)); return; // it's okay, just takes up room } debug("sha1 not equal -- different bytes"); @@ -188,12 +283,12 @@ } debug("%s is a class entry", entryName); if (!fp.isCompatibleVersion(matchFp)) { - main.error(Main.formatMsg("error.validator.incompatible.class.version", entryName)); + error(formatMsg("error.validator.incompatible.class.version", entryName)); isValid = false; return; } if (!fp.isSameAPI(matchFp)) { - main.error(Main.formatMsg("error.validator.different.api", entryName)); + error(formatMsg("error.validator.different.api", entryName)); isValid = false; return; } @@ -208,17 +303,118 @@ } debug("%s is a resource", entryName); - main.warn(Main.formatMsg("warn.validator.resources.with.same.name", entryName)); + warn(formatMsg("warn.validator.resources.with.same.name", entryName)); fps.put(internalName, fp); return; } + private void loadModuleDescriptor() { + ZipEntry je = jf.getEntry(MODULE_INFO); + if (je != null) { + try (InputStream jis = jf.getInputStream(je)) { + md = ModuleDescriptor.read(jis); + concealedPkgs = new HashSet<>(md.packages()); + md.exports().stream().map(Exports::source).forEach(concealedPkgs::remove); + md.opens().stream().map(Opens::source).forEach(concealedPkgs::remove); + return; + } catch (Exception x) { + error(x.getMessage() + " : " + je.getName()); + this.isValid = false; + } + } + md = null; + concealedPkgs = Collections.emptySet(); + } + + private static boolean isPlatformModule(String name) { + return name.startsWith("java.") || name.startsWith("jdk."); + } + + /** + * Checks whether or not the given versioned module descriptor's attributes + * are valid when compared against the root module descriptor. + * + * A versioned module descriptor must be identical to the root module + * descriptor, with two exceptions: + * - A versioned descriptor can have different non-public `requires` + * clauses of platform ( `java.*` and `jdk.*` ) modules, and + * - A versioned descriptor can have different `uses` clauses, even of + * service types defined outside of the platform modules. + */ + private void checkModuleDescriptor(JarEntry je) { + try (InputStream is = jf.getInputStream(je)) { + ModuleDescriptor root = this.md; + ModuleDescriptor md = null; + try { + md = ModuleDescriptor.read(is); + } catch (InvalidModuleDescriptorException x) { + error(x.getMessage()); + isValid = false; + return; + } + if (root == null) { + this.md = md; + } else { + if (!root.name().equals(md.name())) { + error(getMsg("error.versioned.info.name.notequal")); + isValid = false; + } + if (!root.requires().equals(md.requires())) { + Set rootRequires = root.requires(); + for (Requires r : md.requires()) { + if (rootRequires.contains(r)) + continue; + if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) { + error(getMsg("error.versioned.info.requires.transitive")); + isValid = false; + } else if (!isPlatformModule(r.name())) { + error(getMsg("error.versioned.info.requires.added")); + isValid = false; + } + } + for (Requires r : rootRequires) { + Set mdRequires = md.requires(); + if (mdRequires.contains(r)) + continue; + if (!isPlatformModule(r.name())) { + error(getMsg("error.versioned.info.requires.dropped")); + isValid = false; + } + } + } + if (!root.exports().equals(md.exports())) { + error(getMsg("error.versioned.info.exports.notequal")); + isValid = false; + } + if (!root.opens().equals(md.opens())) { + error(getMsg("error.versioned.info.opens.notequal")); + isValid = false; + } + if (!root.provides().equals(md.provides())) { + error(getMsg("error.versioned.info.provides.notequal")); + isValid = false; + } + if (!root.mainClass().equals(md.mainClass())) { + error(formatMsg("error.validator.info.manclass.notequal", je.getName())); + isValid = false; + } + if (!root.version().equals(md.version())) { + error(formatMsg("error.validator.info.version.notequal", je.getName())); + isValid = false; + } + } + } catch (IOException x) { + error(x.getMessage()); + isValid = false; + } + } + private boolean checkInternalName(String entryName, String basename, String internalName) { String className = className(basename); if (internalName.equals(className)) { return true; } - main.error(Main.formatMsg2("error.validator.names.mismatch", + error(formatMsg2("error.validator.names.mismatch", entryName, internalName.replace("/", "."))); return false; } @@ -231,7 +427,7 @@ return true; } debug("top level class was not accepted"); - main.error(Main.formatMsg("error.validator.isolated.nested.class", entryName)); + error(formatMsg("error.validator.isolated.nested.class", entryName)); return false; } @@ -240,16 +436,24 @@ } private boolean isConcealed(String internalName) { - if (main.concealedPackages.isEmpty()) { + if (concealedPkgs.isEmpty()) { return false; } int idx = internalName.lastIndexOf('/'); String pkgName = idx != -1 ? internalName.substring(0, idx).replace('/', '.') : ""; - return main.concealedPackages.contains(pkgName); + return concealedPkgs.contains(pkgName); } private void debug(String fmt, Object... args) { if (DEBUG) System.err.format(fmt, args); } + + private void error(String msg) { + main.error(msg); + } + + private void warn(String msg) { + main.warn(msg); + } + } - diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Wed Jul 05 22:42:01 2017 +0200 @@ -66,23 +66,6 @@ Unexpected module descriptor {0} error.module.descriptor.not.found=\ Module descriptor not found -error.versioned.info.without.root=\ - module-info.class found in a versioned directory without module-info.class \ - in the root -error.versioned.info.name.notequal=\ - module-info.class in a versioned directory contains incorrect name -error.versioned.info.requires.transitive=\ - module-info.class in a versioned directory contains additional "requires transitive" -error.versioned.info.requires.added=\ - module-info.class in a versioned directory contains additional "requires" -error.versioned.info.requires.dropped=\ - module-info.class in a versioned directory contains missing "requires" -error.versioned.info.exports.notequal=\ - module-info.class in a versioned directory contains different "exports" -error.versioned.info.opens.notequal=\ - module-info.class in a versioned directory contains different "opens" -error.versioned.info.provides.notequal=\ - module-info.class in a versioned directory contains different "provides" error.invalid.versioned.module.attribute=\ Invalid module descriptor attribute {0} error.missing.provider=\ @@ -113,6 +96,24 @@ entry: {0}, contains a class with different api from earlier version error.validator.names.mismatch=\ entry: {0}, contains a class with internal name {1}, names do not match +error.validator.info.name.notequal=\ + module-info.class in a versioned directory contains incorrect name +error.validator.info.requires.transitive=\ + module-info.class in a versioned directory contains additional "requires transitive" +error.validator.info.requires.added=\ + module-info.class in a versioned directory contains additional "requires" +error.validator.info.requires.dropped=\ + module-info.class in a versioned directory contains missing "requires" +error.validator.info.exports.notequal=\ + module-info.class in a versioned directory contains different "exports" +error.validator.info.opens.notequal=\ + module-info.class in a versioned directory contains different "opens" +error.validator.info.provides.notequal=\ + module-info.class in a versioned directory contains different "provides" +error.validator.info.version.notequal=\ + {0}: module-info.class in a versioned directory contains different "version" +error.validator.info.manclass.notequal=\ + {0}: module-info.class in a versioned directory contains different "main-class" warn.validator.identical.entry=\ Warning: entry {0} contains a class that\n\ is identical to an entry already in the jar @@ -122,6 +123,8 @@ Warning: entry {0} is a public class\n\ in a concealed package, placing this jar on the class path will result\n\ in incompatible public interfaces +warn.release.unexpected.versioned.entry=\ + unexpected versioned entry {0} out.added.manifest=\ added manifest out.added.module-info=\ diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=--module-version oder --hash-modules ohne module-info.class error.unexpected.module-info=Unerwarteter Moduldeskriptor {0} error.module.descriptor.not.found=Moduldeskriptor nicht gefunden -error.versioned.info.without.root=module-info.class in einem versionierten Verzeichnis gefunden, in der Root ist module-info.class jedoch nicht vorhanden -error.versioned.info.name.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt falschen Namen -error.versioned.info.requires.public=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires public" -error.versioned.info.requires.added=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires" -error.versioned.info.requires.dropped=module-info.class in einem versionierten Verzeichnis enth\u00E4lt fehlenden "requires" -error.versioned.info.exports.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "exports" -error.versioned.info.provides.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "provides" +error.validator.info.without.root=module-info.class in einem versionierten Verzeichnis gefunden, in der Root ist module-info.class jedoch nicht vorhanden +error.validator.info.name.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt falschen Namen +error.validator.info.requires.public=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires public" +error.validator.info.requires.added=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires" +error.validator.info.requires.dropped=module-info.class in einem versionierten Verzeichnis enth\u00E4lt fehlenden "requires" +error.validator.info.exports.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "exports" +error.validator.info.provides.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "provides" error.invalid.versioned.module.attribute=Ung\u00FCltiges Moduldeskriptorattribut {0} error.missing.provider=Serviceprovider nicht gefunden: {0} error.release.value.notnumber=Release {0} nicht g\u00FCltig diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_es.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_es.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_es.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=Uno de --module-version o -hash-modules sin module-info.class error.unexpected.module-info=Descriptor de m\u00F3dulo inesperado {0} error.module.descriptor.not.found=No se ha encontrado el descriptor de m\u00F3dulo -error.versioned.info.without.root=Se ha encontrado module-info.class en un directorio con versi\u00F3n sin module-info.class en la ra\u00EDz -error.versioned.info.name.notequal=module-info.class en un directorio con versi\u00F3n contiene un nombre incorrecto -error.versioned.info.requires.public=module-info.class en un directorio con versiones contiene "requires public" adicionales -error.versioned.info.requires.added=module-info.class en un directorio con versi\u00F3n contiene "requires" adicionales -error.versioned.info.requires.dropped=module-info.class en un directorio con versiones contiene "requires" que faltan -error.versioned.info.exports.notequal=module-info.class en un directorio con versiones contiene "exports" diferentes -error.versioned.info.provides.notequal=module-info.class en un directorio con versiones contiene "provides" diferentes +error.validator.info.without.root=Se ha encontrado module-info.class en un directorio con versi\u00F3n sin module-info.class en la ra\u00EDz +error.validator.info.name.notequal=module-info.class en un directorio con versi\u00F3n contiene un nombre incorrecto +error.validator.info.requires.public=module-info.class en un directorio con versiones contiene "requires public" adicionales +error.validator.info.requires.added=module-info.class en un directorio con versi\u00F3n contiene "requires" adicionales +error.validator.info.requires.dropped=module-info.class en un directorio con versiones contiene "requires" que faltan +error.validator.info.exports.notequal=module-info.class en un directorio con versiones contiene "exports" diferentes +error.validator.info.provides.notequal=module-info.class en un directorio con versiones contiene "provides" diferentes error.invalid.versioned.module.attribute=Atributo de descriptor de m\u00F3dulo no v\u00E1lido {0} error.missing.provider=No se ha encontrado el proveedor de servicios: {0} error.release.value.notnumber=versi\u00F3n {0} no v\u00E1lida diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_fr.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_fr.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_fr.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=Une des options --module-version ou --hash-modules sans module-info.class error.unexpected.module-info=Descripteur de module {0} inattendu error.module.descriptor.not.found=Descripteur de module introuvable -error.versioned.info.without.root=module-info.class a \u00E9t\u00E9 d\u00E9tect\u00E9 dans un r\u00E9pertoire avec num\u00E9ro de version sans module-info.class dans la racine -error.versioned.info.name.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient un nom incorrect -error.versioned.info.requires.public=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires public" suppl\u00E9mentaires -error.versioned.info.requires.added=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" suppl\u00E9mentaires -error.versioned.info.requires.dropped=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" manquants -error.versioned.info.exports.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "exports" diff\u00E9rents -error.versioned.info.provides.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "provides" diff\u00E9rents +error.validator.info.without.root=module-info.class a \u00E9t\u00E9 d\u00E9tect\u00E9 dans un r\u00E9pertoire avec num\u00E9ro de version sans module-info.class dans la racine +error.validator.info.name.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient un nom incorrect +error.validator.info.requires.public=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires public" suppl\u00E9mentaires +error.validator.info.requires.added=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" suppl\u00E9mentaires +error.validator.info.requires.dropped=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" manquants +error.validator.info.exports.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "exports" diff\u00E9rents +error.validator.info.provides.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "provides" diff\u00E9rents error.invalid.versioned.module.attribute=Attribut de descripteur de module non valide {0} error.missing.provider=Fournisseur de services introuvable : {0} error.release.value.notnumber=version {0} non valide diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_it.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_it.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_it.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=Una delle opzioni --module-version o --hash-modules non contiene module-info.class error.unexpected.module-info=Descrittore di modulo {0} imprevisto error.module.descriptor.not.found=Descrittore di modulo non trovato -error.versioned.info.without.root=module-info.class trovato in una directory con controllo delle versioni senza module-info.class nella radice -error.versioned.info.name.notequal=module-info.class in una directory con controllo delle versioni contiene un nome errato -error.versioned.info.requires.public=module-info.class in una directory con controllo delle versioni contiene valori "requires public" aggiuntivi -error.versioned.info.requires.added=module-info.class in una directory con controllo delle versioni contiene valori "requires" aggiuntivi -error.versioned.info.requires.dropped=module-info.class in una directory con controllo delle versioni contiene valori "requires" mancanti -error.versioned.info.exports.notequal=module-info.class in una directory con controllo delle versioni contiene "exports" differenti -error.versioned.info.provides.notequal=module-info.class in una directory con controllo delle versioni contiene valori "provides" differenti +error.validator.info.without.root=module-info.class trovato in una directory con controllo delle versioni senza module-info.class nella radice +error.validator.info.name.notequal=module-info.class in una directory con controllo delle versioni contiene un nome errato +error.validator.info.requires.public=module-info.class in una directory con controllo delle versioni contiene valori "requires public" aggiuntivi +error.validator.info.requires.added=module-info.class in una directory con controllo delle versioni contiene valori "requires" aggiuntivi +error.validator.info.requires.dropped=module-info.class in una directory con controllo delle versioni contiene valori "requires" mancanti +error.validator.info.exports.notequal=module-info.class in una directory con controllo delle versioni contiene "exports" differenti +error.validator.info.provides.notequal=module-info.class in una directory con controllo delle versioni contiene valori "provides" differenti error.invalid.versioned.module.attribute=Attributo descrittore del modulo {0} non valido. error.missing.provider=Provider di servizi non trovato: {0} error.release.value.notnumber=release {0} non valida diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=--module-version\u307E\u305F\u306F--hash-modules\u306E\u3044\u305A\u308C\u304B\u3067module-info.class\u304C\u3042\u308A\u307E\u305B\u3093 error.unexpected.module-info=\u4E88\u671F\u3057\u306A\u3044\u30E2\u30B8\u30E5\u30FC\u30EB\u30FB\u30C7\u30A3\u30B9\u30AF\u30EA\u30D7\u30BF{0} error.module.descriptor.not.found=\u30E2\u30B8\u30E5\u30FC\u30EB\u30FB\u30C7\u30A3\u30B9\u30AF\u30EA\u30D7\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -error.versioned.info.without.root=module-info.class\u304C\u3001\u30EB\u30FC\u30C8\u306Bmodule-info.class\u306E\u306A\u3044\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u898B\u3064\u304B\u308A\u307E\u3057\u305F -error.versioned.info.name.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B63\u3057\u304F\u306A\u3044\u540D\u524D\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 -error.versioned.info.requires.public=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires public"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 -error.versioned.info.requires.added=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 -error.versioned.info.requires.dropped=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B20\u843D\u3057\u3066\u3044\u308B"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 -error.versioned.info.exports.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"exports"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 -error.versioned.info.provides.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"provides"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 +error.validator.info.without.root=module-info.class\u304C\u3001\u30EB\u30FC\u30C8\u306Bmodule-info.class\u306E\u306A\u3044\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u898B\u3064\u304B\u308A\u307E\u3057\u305F +error.validator.info.name.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B63\u3057\u304F\u306A\u3044\u540D\u524D\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 +error.validator.info.requires.public=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires public"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 +error.validator.info.requires.added=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 +error.validator.info.requires.dropped=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B20\u843D\u3057\u3066\u3044\u308B"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 +error.validator.info.exports.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"exports"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 +error.validator.info.provides.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"provides"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 error.invalid.versioned.module.attribute=\u30E2\u30B8\u30E5\u30FC\u30EB\u30FB\u30C7\u30A3\u30B9\u30AF\u30EA\u30D7\u30BF\u5C5E\u6027{0}\u304C\u7121\u52B9\u3067\u3059 error.missing.provider=\u30B5\u30FC\u30D3\u30B9\u30FB\u30D7\u30ED\u30D0\u30A4\u30C0\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: {0} error.release.value.notnumber=\u30EA\u30EA\u30FC\u30B9{0}\u306F\u6709\u52B9\u3067\u306F\u3042\u308A\u307E\u305B\u3093 diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ko.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ko.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ko.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=module-info.class \uC5C6\uC774 --module-version \uB610\uB294 --hash-modules \uC911 \uD558\uB098 error.unexpected.module-info=\uC608\uC0C1\uCE58 \uC54A\uC740 \uBAA8\uB4C8 \uAE30\uC220\uC790 {0} error.module.descriptor.not.found=\uBAA8\uB4C8 \uAE30\uC220\uC790\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC74C -error.versioned.info.without.root=\uB8E8\uD2B8\uC5D0\uC11C module-info.class \uC5C6\uC774 \uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C module-info.class\uAC00 \uBC1C\uACAC\uB428 -error.versioned.info.name.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uC798\uBABB\uB41C \uC774\uB984\uC774 \uD3EC\uD568\uB428 -error.versioned.info.requires.public=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires public" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 -error.versioned.info.requires.added=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 -error.versioned.info.requires.dropped=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB204\uB77D\uB41C "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 -error.versioned.info.exports.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "exports" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 -error.versioned.info.provides.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "provides" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 +error.validator.info.without.root=\uB8E8\uD2B8\uC5D0\uC11C module-info.class \uC5C6\uC774 \uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C module-info.class\uAC00 \uBC1C\uACAC\uB428 +error.validator.info.name.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uC798\uBABB\uB41C \uC774\uB984\uC774 \uD3EC\uD568\uB428 +error.validator.info.requires.public=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires public" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 +error.validator.info.requires.added=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 +error.validator.info.requires.dropped=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB204\uB77D\uB41C "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 +error.validator.info.exports.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "exports" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 +error.validator.info.provides.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "provides" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428 error.invalid.versioned.module.attribute=\uBD80\uC801\uD569\uD55C \uBAA8\uB4C8 \uAE30\uC220\uC790 \uC18D\uC131 {0} error.missing.provider=\uC11C\uBE44\uC2A4 \uC81C\uACF5\uC790\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC74C: {0} error.release.value.notnumber=\uB9B4\uB9AC\uC2A4 {0}\uC774(\uAC00) \uBD80\uC801\uD569\uD568 diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_pt_BR.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_pt_BR.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_pt_BR.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=Um dentre --module-version ou --hash-modules est\u00E1 sem module-info.class error.unexpected.module-info=Descritor de m\u00F3dulo inesperado {0} error.module.descriptor.not.found=Descritor de m\u00F3dulo n\u00E3o encontrado -error.versioned.info.without.root=module-info.class encontrado em um diret\u00F3rio com controle de vers\u00E3o sem module-info.class na raiz -error.versioned.info.name.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m nome incorreto -error.versioned.info.requires.public=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires public" adicional -error.versioned.info.requires.added=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires" adicional -error.versioned.info.requires.dropped=module-info.class em um diret\u00F3rio com controle de vers\u00E3o falta "requires" -error.versioned.info.exports.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "exports" diferente -error.versioned.info.provides.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "provides" diferente +error.validator.info.without.root=module-info.class encontrado em um diret\u00F3rio com controle de vers\u00E3o sem module-info.class na raiz +error.validator.info.name.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m nome incorreto +error.validator.info.requires.public=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires public" adicional +error.validator.info.requires.added=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires" adicional +error.validator.info.requires.dropped=module-info.class em um diret\u00F3rio com controle de vers\u00E3o falta "requires" +error.validator.info.exports.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "exports" diferente +error.validator.info.provides.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "provides" diferente error.invalid.versioned.module.attribute=Atributo {0} de descritor de m\u00F3dulo inv\u00E1lido error.missing.provider=Prestador de servi\u00E7os n\u00E3o encontrado: {0} error.release.value.notnumber=release {0} n\u00E3o v\u00E1lida diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_sv.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_sv.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_sv.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=--module-version eller --hash-modules utan module-info.class error.unexpected.module-info=Ov\u00E4ntad moduldeskriptor, {0} error.module.descriptor.not.found=Moduldeskriptorn hittades inte -error.versioned.info.without.root=module-info.class hittades i en versionshanterad katalog utan module-info.class i roten -error.versioned.info.name.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller ett felaktigt namn -error.versioned.info.requires.public=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires public" -error.versioned.info.requires.added=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires" -error.versioned.info.requires.dropped=module-info.class i en versionshanterad katalog inneh\u00E5ller saknade "requires" -error.versioned.info.exports.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "exports" -error.versioned.info.provides.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "provides" +error.validator.info.without.root=module-info.class hittades i en versionshanterad katalog utan module-info.class i roten +error.validator.info.name.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller ett felaktigt namn +error.validator.info.requires.public=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires public" +error.validator.info.requires.added=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires" +error.validator.info.requires.dropped=module-info.class i en versionshanterad katalog inneh\u00E5ller saknade "requires" +error.validator.info.exports.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "exports" +error.validator.info.provides.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "provides" error.invalid.versioned.module.attribute=Ogiltigt attribut f\u00F6r moduldeskriptor, {0} error.missing.provider=Tj\u00E4nsteleverant\u00F6ren hittades inte: {0} error.release.value.notnumber=utg\u00E5va {0} \u00E4r inte giltig diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=--module-version \u6216 --hash-modules \u4E4B\u4E00\u6CA1\u6709 module-info.class error.unexpected.module-info=\u610F\u5916\u7684\u6A21\u5757\u63CF\u8FF0\u7B26 {0} error.module.descriptor.not.found=\u627E\u4E0D\u5230\u6A21\u5757\u63CF\u8FF0\u7B26 -error.versioned.info.without.root=\u5728\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u627E\u5230\u4E86 module-info.class, \u4F46\u6839\u4E2D\u6CA1\u6709 module-info.class -error.versioned.info.name.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u786E\u7684\u540D\u79F0 -error.versioned.info.requires.public=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires public" -error.versioned.info.requires.added=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires" -error.versioned.info.requires.dropped=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u7F3A\u5C11\u7684 "requires" -error.versioned.info.exports.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports" -error.versioned.info.provides.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides" +error.validator.info.without.root=\u5728\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u627E\u5230\u4E86 module-info.class, \u4F46\u6839\u4E2D\u6CA1\u6709 module-info.class +error.validator.info.name.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u786E\u7684\u540D\u79F0 +error.validator.info.requires.public=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires public" +error.validator.info.requires.added=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires" +error.validator.info.requires.dropped=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u7F3A\u5C11\u7684 "requires" +error.validator.info.exports.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports" +error.validator.info.provides.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides" error.invalid.versioned.module.attribute=\u65E0\u6548\u7684\u6A21\u5757\u63CF\u8FF0\u7B26\u5C5E\u6027 {0} error.missing.provider=\u672A\u627E\u5230\u670D\u52A1\u63D0\u4F9B\u65B9: {0} error.release.value.notnumber=\u53D1\u884C\u7248 {0} \u65E0\u6548 diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_TW.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_TW.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_TW.properties Wed Jul 05 22:42:01 2017 +0200 @@ -42,13 +42,13 @@ error.module.options.without.info=--module-version \u6216 --hash-modules \u5176\u4E2D\u4E00\u500B\u6C92\u6709 module-info.class error.unexpected.module-info=\u672A\u9810\u671F\u7684\u6A21\u7D44\u63CF\u8FF0\u5340 {0} error.module.descriptor.not.found=\u627E\u4E0D\u5230\u6A21\u7D44\u63CF\u8FF0\u5340 -error.versioned.info.without.root=\u5728\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u767C\u73FE module-info.class\uFF0C\u4F46\u662F\u6839\u4E2D\u6C92\u6709 module-info.class -error.versioned.info.name.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u78BA\u7684\u540D\u7A31 -error.versioned.info.requires.public=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires public" -error.versioned.info.requires.added=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires" -error.versioned.info.requires.dropped=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u907A\u6F0F\u7684 "requires" -error.versioned.info.exports.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports" -error.versioned.info.provides.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides" +error.validator.info.without.root=\u5728\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u767C\u73FE module-info.class\uFF0C\u4F46\u662F\u6839\u4E2D\u6C92\u6709 module-info.class +error.validator.info.name.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u78BA\u7684\u540D\u7A31 +error.validator.info.requires.public=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires public" +error.validator.info.requires.added=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires" +error.validator.info.requires.dropped=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u907A\u6F0F\u7684 "requires" +error.validator.info.exports.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports" +error.validator.info.provides.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides" error.invalid.versioned.module.attribute=\u6A21\u7D44\u63CF\u8FF0\u5340\u5C6C\u6027 {0} \u7121\u6548 error.missing.provider=\u627E\u4E0D\u5230\u670D\u52D9\u63D0\u4F9B\u8005: {0} error.release.value.notnumber=\u7248\u672C {0} \u7121\u6548 diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,13 +58,10 @@ import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.text.MessageFormat; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Deque; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -101,6 +98,7 @@ import jdk.internal.joptsimple.ValueConverter; import jdk.internal.loader.ResourceHelper; import jdk.internal.module.ModuleHashes; +import jdk.internal.module.ModuleHashesBuilder; import jdk.internal.module.ModuleInfo; import jdk.internal.module.ModuleInfoExtender; import jdk.internal.module.ModulePath; @@ -286,7 +284,27 @@ } private boolean hashModules() { - return new Hasher(options.moduleFinder).run(); + if (options.dryrun) { + out.println("Dry run:"); + } + + Hasher hasher = new Hasher(options.moduleFinder); + hasher.computeHashes().forEach((mn, hashes) -> { + if (options.dryrun) { + out.format("%s%n", mn); + hashes.names().stream() + .sorted() + .forEach(name -> out.format(" hashes %s %s %s%n", + name, hashes.algorithm(), toHex(hashes.hashFor(name)))); + } else { + try { + hasher.updateModuleInfo(mn, hashes); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + }); + return true; } private boolean describe() throws IOException { @@ -377,7 +395,7 @@ // create jmod with temporary name to avoid it being examined // when scanning the module path Path target = options.jmodFile; - Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp"); + Path tempTarget = Files.createTempFile(target.getFileName().toString(), ".tmp"); try { try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) { jmod.write(jos); @@ -411,7 +429,6 @@ final String osArch = options.osArch; final String osVersion = options.osVersion; final List excludes = options.excludes; - final Hasher hasher = hasher(); final ModuleResolution moduleResolution = options.moduleResolution; JmodFileWriter() { } @@ -514,8 +531,17 @@ if (moduleVersion != null) extender.version(moduleVersion); - if (hasher != null) { - ModuleHashes moduleHashes = hasher.computeHashes(descriptor.name()); + // --hash-modules + if (options.modulesToHash != null) { + // To compute hashes, it creates a Configuration to resolve + // a module graph. The post-resolution check requires + // the packages in ModuleDescriptor be available for validation. + ModuleDescriptor md; + try (InputStream is = miSupplier.get()) { + md = ModuleDescriptor.read(is, () -> packages); + } + + ModuleHashes moduleHashes = computeHashes(md); if (moduleHashes != null) { extender.hashes(moduleHashes); } else { @@ -557,50 +583,34 @@ * The jmod file is being created and does not exist in the * given modulepath. */ - private Hasher hasher() { - if (options.modulesToHash == null) - return null; - - try { - Supplier miSupplier = newModuleInfoSupplier(); - if (miSupplier == null) { - throw new IOException(MODULE_INFO + " not found"); + private ModuleHashes computeHashes(ModuleDescriptor descriptor) { + String mn = descriptor.name(); + URI uri = options.jmodFile.toUri(); + ModuleReference mref = new ModuleReference(descriptor, uri) { + @Override + public ModuleReader open() { + throw new UnsupportedOperationException("opening " + mn); } + }; - ModuleDescriptor descriptor; - try (InputStream in = miSupplier.get()) { - descriptor = ModuleDescriptor.read(in); - } - - URI uri = options.jmodFile.toUri(); - ModuleReference mref = new ModuleReference(descriptor, uri) { + // compose a module finder with the module path and also + // a module finder that can find the jmod file being created + ModuleFinder finder = ModuleFinder.compose(options.moduleFinder, + new ModuleFinder() { @Override - public ModuleReader open() { - throw new UnsupportedOperationException(); + public Optional find(String name) { + if (descriptor.name().equals(name)) + return Optional.of(mref); + else return Optional.empty(); } - }; - // compose a module finder with the module path and also - // a module finder that can find the jmod file being created - ModuleFinder finder = ModuleFinder.compose(options.moduleFinder, - new ModuleFinder() { - @Override - public Optional find(String name) { - if (descriptor.name().equals(name)) - return Optional.of(mref); - else return Optional.empty(); - } + @Override + public Set findAll() { + return Collections.singleton(mref); + } + }); - @Override - public Set findAll() { - return Collections.singleton(mref); - } - }); - - return new Hasher(finder); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + return new Hasher(mn, finder).computeHashes().get(mn); } /** @@ -789,192 +799,93 @@ * Compute and record hashes */ private class Hasher { - final ModuleFinder moduleFinder; - final Map moduleNameToPath; + final Configuration configuration; + final ModuleHashesBuilder hashesBuilder; final Set modules; - final Configuration configuration; - final boolean dryrun = options.dryrun; + final String moduleName; // a specific module to record hashes, if set + + /** + * This constructor is for jmod hash command. + * + * This Hasher will determine which modules to record hashes, i.e. + * the module in a subgraph of modules to be hashed and that + * has no outgoing edges. It will record in each of these modules, + * say `M`, with the the hashes of modules that depend upon M + * directly or indirectly matching the specified --hash-modules pattern. + */ Hasher(ModuleFinder finder) { - this.moduleFinder = finder; + this(null, finder); + } + + /** + * Constructs a Hasher to compute hashes. + * + * If a module name `M` is specified, it will compute the hashes of + * modules that depend upon M directly or indirectly matching the + * specified --hash-modules pattern and record in the ModuleHashes + * attribute in M's module-info.class. + * + * @param name name of the module to record hashes + * @param finder module finder for the specified --module-path + */ + Hasher(String name, ModuleFinder finder) { // Determine the modules that matches the pattern {@code modulesToHash} - this.modules = moduleFinder.findAll().stream() + Set roots = finder.findAll().stream() .map(mref -> mref.descriptor().name()) .filter(mn -> options.modulesToHash.matcher(mn).find()) .collect(Collectors.toSet()); - // a map from a module name to Path of the packaged module - this.moduleNameToPath = moduleFinder.findAll().stream() - .map(mref -> mref.descriptor().name()) - .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn))); - + // use system module path unless it creates a JMOD file for + // a module that is present in the system image e.g. upgradeable + // module + ModuleFinder system; + if (name != null && ModuleFinder.ofSystem().find(name).isPresent()) { + system = ModuleFinder.of(); + } else { + system = ModuleFinder.ofSystem(); + } // get a resolved module graph Configuration config = null; try { - config = Configuration.empty() - .resolveRequires(ModuleFinder.ofSystem(), moduleFinder, modules); + config = Configuration.empty().resolveRequires(system, finder, roots); } catch (ResolutionException e) { - warning("warn.module.resolution.fail", e.getMessage()); + throw new CommandException("err.module.resolution.fail", e.getMessage()); } + + this.moduleName = name; this.configuration = config; + + // filter modules resolved from the system module finder + this.modules = config.modules().stream() + .map(ResolvedModule::name) + .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent()) + .collect(Collectors.toSet()); + + this.hashesBuilder = new ModuleHashesBuilder(config, modules); } /** - * This method is for jmod hash command. + * Returns a map of a module M to record hashes of the modules + * that depend upon M directly or indirectly. * - * Identify the base modules in the module graph, i.e. no outgoing edge - * to any of the modules to be hashed. + * For jmod hash command, the returned map contains one entry + * for each module M that has no outgoing edges to any of the + * modules matching the specified --hash-modules pattern. * - * For each base module M, compute the hashes of all modules that depend - * upon M directly or indirectly. Then update M's module-info.class - * to record the hashes. + * Each entry represents a leaf node in a connected subgraph containing + * M and other candidate modules from the module graph where M's outgoing + * edges to any module other than the ones matching the specified + * --hash-modules pattern are excluded. */ - boolean run() { - if (configuration == null) - return false; - - // transposed graph containing the the packaged modules and - // its transitive dependences matching --hash-modules - Map> graph = new HashMap<>(); - for (String root : modules) { - Deque deque = new ArrayDeque<>(); - deque.add(root); - Set visited = new HashSet<>(); - while (!deque.isEmpty()) { - String mn = deque.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - - if (modules.contains(mn)) - graph.computeIfAbsent(mn, _k -> new HashSet<>()); - - ResolvedModule resolvedModule = configuration.findModule(mn).get(); - for (ResolvedModule dm : resolvedModule.reads()) { - String name = dm.name(); - if (!visited.contains(name)) { - deque.push(name); - } - - // reverse edge - if (modules.contains(name) && modules.contains(mn)) { - graph.computeIfAbsent(name, _k -> new HashSet<>()).add(mn); - } - } - } - } - } - - if (dryrun) - out.println("Dry run:"); - - // each node in a transposed graph is a matching packaged module - // in which the hash of the modules that depend upon it is recorded - graph.entrySet().stream() - .filter(e -> !e.getValue().isEmpty()) - .forEach(e -> { - String mn = e.getKey(); - Map modulesForHash = e.getValue().stream() - .collect(Collectors.toMap(Function.identity(), - moduleNameToPath::get)); - ModuleHashes hashes = ModuleHashes.generate(modulesForHash, "SHA-256"); - if (dryrun) { - out.format("%s%n", mn); - hashes.names().stream() - .sorted() - .forEach(name -> out.format(" hashes %s %s %s%n", - name, hashes.algorithm(), hashes.hashFor(name))); - } else { - try { - updateModuleInfo(mn, hashes); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - }); - return true; - } - - /** - * Compute hashes of the specified module. - * - * It records the hashing modules that depend upon the specified - * module directly or indirectly. - */ - ModuleHashes computeHashes(String name) { - if (configuration == null) + Map computeHashes() { + if (hashesBuilder == null) return null; - // the transposed graph includes all modules in the resolved graph - Map> graph = transpose(); - - // find the modules that transitively depend upon the specified name - Deque deque = new ArrayDeque<>(); - deque.add(name); - Set mods = visitNodes(graph, deque); - - // filter modules matching the pattern specified --hash-modules - // as well as itself as the jmod file is being generated - Map modulesForHash = mods.stream() - .filter(mn -> !mn.equals(name) && modules.contains(mn)) - .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get)); - - if (modulesForHash.isEmpty()) - return null; - - return ModuleHashes.generate(modulesForHash, "SHA-256"); - } - - /** - * Returns all nodes traversed from the given roots. - */ - private Set visitNodes(Map> graph, - Deque roots) { - Set visited = new HashSet<>(); - while (!roots.isEmpty()) { - String mn = roots.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - // the given roots may not be part of the graph - if (graph.containsKey(mn)) { - for (String dm : graph.get(mn)) { - if (!visited.contains(dm)) { - roots.push(dm); - } - } - } - } + if (moduleName != null) { + return hashesBuilder.computeHashes(Set.of(moduleName)); + } else { + return hashesBuilder.computeHashes(modules); } - return visited; - } - - /** - * Returns a transposed graph from the resolved module graph. - */ - private Map> transpose() { - Map> transposedGraph = new HashMap<>(); - Deque deque = new ArrayDeque<>(modules); - - Set visited = new HashSet<>(); - while (!deque.isEmpty()) { - String mn = deque.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - - transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>()); - - ResolvedModule resolvedModule = configuration.findModule(mn).get(); - for (ResolvedModule dm : resolvedModule.reads()) { - String name = dm.name(); - if (!visited.contains(name)) { - deque.push(name); - } - - // reverse edge - transposedGraph.computeIfAbsent(name, _k -> new HashSet<>()) - .add(mn); - } - } - } - return transposedGraph; } /** @@ -993,11 +904,11 @@ extender.write(out); } - private void updateModuleInfo(String name, ModuleHashes moduleHashes) + void updateModuleInfo(String name, ModuleHashes moduleHashes) throws IOException { - Path target = moduleNameToPath.get(name); - Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp"); + Path target = moduleToPath(name); + Path tempTarget = Files.createTempFile(target.getFileName().toString(), ".tmp"); try { if (target.getFileName().toString().endsWith(".jmod")) { updateJmodFile(target, tempTarget, moduleHashes); @@ -1075,10 +986,10 @@ } private Path moduleToPath(String name) { - ModuleReference mref = moduleFinder.find(name).orElseThrow( + ResolvedModule rm = configuration.findModule(name).orElseThrow( () -> new InternalError("Selected module " + name + " not on module path")); - URI uri = mref.location().get(); + URI uri = rm.reference().location().get(); Path path = Paths.get(uri); String fn = path.getFileName().toString(); if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) { @@ -1088,34 +999,58 @@ } } - static class ClassPathConverter implements ValueConverter { - static final ValueConverter INSTANCE = new ClassPathConverter(); + /** + * An abstract converter that given a string representing a list of paths, + * separated by the File.pathSeparator, returns a List of java.nio.Path's. + * Specific subclasses should do whatever validation is required on the + * individual path elements, if any. + */ + static abstract class AbstractPathConverter implements ValueConverter> { + @Override + public List convert(String value) { + List paths = new ArrayList<>(); + String[] pathElements = value.split(File.pathSeparator); + for (String pathElement : pathElements) { + paths.add(toPath(pathElement)); + } + return paths; + } + + @SuppressWarnings("unchecked") + @Override + public Class> valueType() { + return (Class>)(Object)List.class; + } + + @Override public String valuePattern() { return "path"; } + + abstract Path toPath(String path); + } + + static class ClassPathConverter extends AbstractPathConverter { + static final ValueConverter> INSTANCE = new ClassPathConverter(); @Override - public Path convert(String value) { + public Path toPath(String value) { try { Path path = CWD.resolve(value); if (Files.notExists(path)) throw new CommandException("err.path.not.found", path); - if (! (Files.isDirectory(path) || - (Files.isRegularFile(path) && path.toString().endsWith(".jar")))) + if (!(Files.isDirectory(path) || + (Files.isRegularFile(path) && path.toString().endsWith(".jar")))) throw new CommandException("err.invalid.class.path.entry", path); return path; } catch (InvalidPathException x) { throw new CommandException("err.path.not.valid", value); } } - - @Override public Class valueType() { return Path.class; } - - @Override public String valuePattern() { return "path"; } } - static class DirPathConverter implements ValueConverter { - static final ValueConverter INSTANCE = new DirPathConverter(); + static class DirPathConverter extends AbstractPathConverter { + static final ValueConverter> INSTANCE = new DirPathConverter(); @Override - public Path convert(String value) { + public Path toPath(String value) { try { Path path = CWD.resolve(value); if (Files.notExists(path)) @@ -1127,10 +1062,6 @@ throw new CommandException("err.path.not.valid", value); } } - - @Override public Class valueType() { return Path.class; } - - @Override public String valuePattern() { return "path"; } } static class ExtractDirPathConverter implements ValueConverter { @@ -1142,12 +1073,6 @@ if (Files.exists(path)) { if (!Files.isDirectory(path)) throw new CommandException("err.cannot.create.dir", path); - } else { - try { - Files.createDirectories(path); - } catch (IOException ioe) { - throw new CommandException("err.cannot.create.dir", path); - } } return path; } catch (InvalidPathException x) { @@ -1316,22 +1241,19 @@ options = new Options(); parser.formatHelpWith(new JmodHelpFormatter(options)); - OptionSpec classPath + OptionSpec> classPath = parser.accepts("class-path", getMessage("main.opt.class-path")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(ClassPathConverter.INSTANCE); - OptionSpec cmds + OptionSpec> cmds = parser.accepts("cmds", getMessage("main.opt.cmds")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); - OptionSpec config + OptionSpec> config = parser.accepts("config", getMessage("main.opt.config")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); OptionSpec dir @@ -1359,22 +1281,19 @@ OptionSpec helpExtra = parser.accepts("help-extra", getMessage("main.opt.help-extra")); - OptionSpec headerFiles + OptionSpec> headerFiles = parser.accepts("header-files", getMessage("main.opt.header-files")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); - OptionSpec libs + OptionSpec> libs = parser.accepts("libs", getMessage("main.opt.libs")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); - OptionSpec legalNotices + OptionSpec> legalNotices = parser.accepts("legal-notices", getMessage("main.opt.legal-notices")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); @@ -1383,17 +1302,15 @@ .withRequiredArg() .describedAs(getMessage("main.opt.main-class.arg")); - OptionSpec manPages + OptionSpec> manPages = parser.accepts("man-pages", getMessage("main.opt.man-pages")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); - OptionSpec modulePath + OptionSpec> modulePath = parser.acceptsAll(Set.of("p", "module-path"), getMessage("main.opt.module-path")) .withRequiredArg() - .withValuesSeparatedBy(File.pathSeparatorChar) .withValuesConvertedBy(DirPathConverter.INSTANCE); OptionSpec moduleVersion @@ -1452,48 +1369,48 @@ } if (opts.has(classPath)) - options.classpath = opts.valuesOf(classPath); + options.classpath = getLastElement(opts.valuesOf(classPath)); if (opts.has(cmds)) - options.cmds = opts.valuesOf(cmds); + options.cmds = getLastElement(opts.valuesOf(cmds)); if (opts.has(config)) - options.configs = opts.valuesOf(config); + options.configs = getLastElement(opts.valuesOf(config)); if (opts.has(dir)) - options.extractDir = opts.valueOf(dir); + options.extractDir = getLastElement(opts.valuesOf(dir)); if (opts.has(dryrun)) options.dryrun = true; if (opts.has(excludes)) - options.excludes = opts.valuesOf(excludes); + options.excludes = opts.valuesOf(excludes); // excludes is repeatable if (opts.has(libs)) - options.libs = opts.valuesOf(libs); + options.libs = getLastElement(opts.valuesOf(libs)); if (opts.has(headerFiles)) - options.headerFiles = opts.valuesOf(headerFiles); + options.headerFiles = getLastElement(opts.valuesOf(headerFiles)); if (opts.has(manPages)) - options.manPages = opts.valuesOf(manPages); + options.manPages = getLastElement(opts.valuesOf(manPages)); if (opts.has(legalNotices)) - options.legalNotices = opts.valuesOf(legalNotices); + options.legalNotices = getLastElement(opts.valuesOf(legalNotices)); if (opts.has(modulePath)) { - Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]); + Path[] dirs = getLastElement(opts.valuesOf(modulePath)).toArray(new Path[0]); options.moduleFinder = new ModulePath(Runtime.version(), true, dirs); } if (opts.has(moduleVersion)) - options.moduleVersion = opts.valueOf(moduleVersion); + options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion)); if (opts.has(mainClass)) - options.mainClass = opts.valueOf(mainClass); + options.mainClass = getLastElement(opts.valuesOf(mainClass)); if (opts.has(osName)) - options.osName = opts.valueOf(osName); + options.osName = getLastElement(opts.valuesOf(osName)); if (opts.has(osArch)) - options.osArch = opts.valueOf(osArch); + options.osArch = getLastElement(opts.valuesOf(osArch)); if (opts.has(osVersion)) - options.osVersion = opts.valueOf(osVersion); + options.osVersion = getLastElement(opts.valuesOf(osVersion)); if (opts.has(warnIfResolved)) - options.moduleResolution = opts.valueOf(warnIfResolved); + options.moduleResolution = getLastElement(opts.valuesOf(warnIfResolved)); if (opts.has(doNotResolveByDefault)) { if (options.moduleResolution == null) options.moduleResolution = ModuleResolution.empty(); options.moduleResolution = options.moduleResolution.withDoNotResolveByDefault(); } if (opts.has(hashModules)) { - options.modulesToHash = opts.valueOf(hashModules); + options.modulesToHash = getLastElement(opts.valuesOf(hashModules)); // if storing hashes then the module path is required if (options.moduleFinder == null) throw new CommandException("err.modulepath.must.be.specified") @@ -1531,6 +1448,13 @@ throw new CommandException("err.classpath.must.be.specified").showUsage(true); if (options.mainClass != null && !isValidJavaIdentifier(options.mainClass)) throw new CommandException("err.invalid.main-class", options.mainClass); + if (options.mode.equals(Mode.EXTRACT) && options.extractDir != null) { + try { + Files.createDirectories(options.extractDir); + } catch (IOException ioe) { + throw new CommandException("err.cannot.create.dir", options.extractDir); + } + } } catch (OptionException e) { throw new CommandException(e.getMessage()); } @@ -1558,6 +1482,12 @@ return true; } + static E getLastElement(List list) { + if (list.size() == 0) + throw new InternalError("Unexpected 0 list size"); + return list.get(list.size() - 1); + } + private void reportError(String message) { out.println(getMessage("error.prefix") + " " + message); } diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties Wed Jul 05 22:42:01 2017 +0200 @@ -108,9 +108,9 @@ err.invalid.dryrun.option=--dry-run can only be used with hash mode err.module.descriptor.not.found=Module descriptor not found err.missing.export.or.open.packages=Packages that are exported or open in {0} are not present: {1} +err.module.resolution.fail=Resolution failed: {0} warn.invalid.arg=Invalid classname or pathname not exist: {0} warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0} -warn.module.resolution.fail=No hashes recorded: {0} warn.ignore.entry=ignoring entry {0}, in section {1} warn.ignore.duplicate.entry=ignoring duplicate entry {0}, in section {1} diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c --- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c Wed Jul 05 22:42:01 2017 +0200 @@ -418,7 +418,6 @@ (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj, jlong address, jint length, jboolean peek) { SOCKETADDRESS sa; - int sa_len = sizeof(SOCKETADDRESS); ssize_t rv = 0; jlong *addr = jlong_to_ptr(address); struct iovec iov[1]; @@ -429,7 +428,7 @@ /* Set up the msghdr structure for receiving */ memset(msg, 0, sizeof (*msg)); msg->msg_name = &sa; - msg->msg_namelen = sa_len; + msg->msg_namelen = sizeof(sa); iov->iov_base = addr; iov->iov_len = length; msg->msg_iov = iov; @@ -538,7 +537,7 @@ jobject targetAddress, jint targetPort, jint assocId, jint streamNumber, jboolean unordered, jint ppid) { SOCKETADDRESS sa; - int sa_len = sizeof(SOCKETADDRESS); + int sa_len = 0; ssize_t rv = 0; jlong *addr = jlong_to_ptr(address); struct iovec iov[1]; @@ -555,13 +554,12 @@ * Association already existing, assocId != -1, targetAddress = preferred addr */ if (targetAddress != NULL /*&& assocId <= 0*/) { - if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, &sa.sa, + if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, &sa, &sa_len, JNI_TRUE) != 0) { return IOS_THROWN; } } else { - memset(&sa, '\x0', sa_len); - sa_len = 0; + memset(&sa, '\x0', sizeof(sa)); } /* Set up the msghdr structure for sending */ diff -r 047a57b0839a -r 1c9922f121ff jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c Wed Jul 05 22:42:01 2017 +0200 @@ -211,22 +211,22 @@ (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port, jint addrsLength, jboolean add, jboolean preferIPv6) { SOCKETADDRESS *sap, *tmpSap; - int i, sa_len = sizeof(SOCKETADDRESS); + int i; jobject ia; if (addrsLength < 1) return; - if ((sap = calloc(addrsLength, sa_len)) == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failure"); + if ((sap = calloc(addrsLength, sizeof(SOCKETADDRESS))) == NULL) { + JNU_ThrowOutOfMemoryError(env, "heap allocation failure"); return; } tmpSap = sap; for (i = 0; i < addrsLength; i++) { ia = (*env)->GetObjectArrayElement(env, addrs, i); - if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr*)tmpSap, - &sa_len, preferIPv6) != 0) { + if (NET_InetAddressToSockaddr(env, ia, port, tmpSap, NULL, + preferIPv6) != 0) { free(sap); return; } @@ -262,11 +262,11 @@ Java_sun_nio_ch_sctp_SctpNet_connect0 (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) { SOCKETADDRESS sa; - int sa_len = sizeof(SOCKETADDRESS); + int sa_len = 0; int rv; - if (NET_InetAddressToSockaddr(env, iao, port, &sa.sa, - &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, + JNI_TRUE) != 0) { return IOS_THROWN; } @@ -311,8 +311,7 @@ } } -void initializeISA - (JNIEnv* env) { +void initializeISA(JNIEnv* env) { if (isaCls == 0) { jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); CHECK_NULL(c); @@ -325,8 +324,7 @@ } } -jobject SockAddrToInetSocketAddress - (JNIEnv *env, struct sockaddr* sap) { +jobject SockAddrToInetSocketAddress(JNIEnv *env, SOCKETADDRESS *sap) { int port = 0; jobject ia = NET_SockaddrToInetAddress(env, sap, &port); @@ -347,9 +345,9 @@ * Signature: (I)[Ljava/net/SocketAddress; */ JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0 - (JNIEnv *env, jclass klass, jint fd) { + (JNIEnv *env, jclass klass, jint fd) +{ void *addr_buf, *laddr; - struct sockaddr* sap; int i, addrCount; jobjectArray isaa; @@ -377,38 +375,35 @@ } laddr = addr_buf; - for (i=0; iNewObject(env, isaCls, isaCtrID, ia, port); if (isa == NULL) break; (*env)->SetObjectArrayElement(env, isaa, i, isa); - if (sap->sa_family == AF_INET) - addr_buf = ((struct sockaddr_in*)addr_buf) + 1; + if (((struct sockaddr *)addr_buf)->sa_family == AF_INET) + addr_buf = ((struct sockaddr_in *)addr_buf) + 1; else - addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; + addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1; } nio_sctp_freeladdrs(laddr); return isaa; } -jobjectArray getRemoteAddresses - (JNIEnv *env, jint fd, sctp_assoc_t id) { +jobjectArray getRemoteAddresses(JNIEnv *env, jint fd, sctp_assoc_t id) { void *addr_buf, *paddr; - struct sockaddr* sap; int i, addrCount; jobjectArray isaa; #if __solaris__ if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) { #else /* __linux__ */ - if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) { + if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) { #endif handleSocketError(env, errno); return NULL; @@ -429,25 +424,23 @@ } paddr = addr_buf; - for (i=0; iNewObject(env, isaCls, isaCtrID, ia, port); if (isa == NULL) break; (*env)->SetObjectArrayElement(env, isaa, i, isa); - if (sap->sa_family == AF_INET) - addr_buf = ((struct sockaddr_in*)addr_buf) + 1; + if (((struct sockaddr *)addr_buf)->sa_family == AF_INET) + addr_buf = ((struct sockaddr_in *)addr_buf) + 1; else - addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; + addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1; } nio_sctp_freepaddrs(paddr); - return isaa; } @@ -579,7 +572,6 @@ (JNIEnv *env, jclass klass, jint fd, jint assocId) { struct sctp_setprim prim; unsigned int prim_len = sizeof(prim); - struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr; prim.ssp_assoc_id = assocId; @@ -589,7 +581,7 @@ return NULL; } - return SockAddrToInetSocketAddress(env, sap); + return SockAddrToInetSocketAddress(env, (SOCKETADDRESS *)&prim.ssp_addr); } /* @@ -600,11 +592,10 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) { struct sctp_setprim prim; - struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr; - int sap_len = sizeof(sap); - if (NET_InetAddressToSockaddr(env, iaObj, port, sap, - &sap_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, port, + (SOCKETADDRESS *)&prim.ssp_addr, + NULL, JNI_TRUE) != 0) { return; } @@ -625,18 +616,17 @@ (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port, jboolean preferIPv6) { struct sctp_setpeerprim prim; - struct sockaddr* sap = (struct sockaddr*)&prim.sspp_addr; - int sap_len = sizeof(sap); - if (NET_InetAddressToSockaddr(env, iaObj, port, sap, - &sap_len, preferIPv6) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, port, + (SOCKETADDRESS *)&prim.sspp_addr, + NULL, preferIPv6) != 0) { return; } prim.sspp_assoc_id = assocId; if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim, - sizeof(prim)) < 0) { + sizeof(prim)) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.SctpNet.setPeerPrimAddrOption0"); } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/ProblemList.txt Wed Jul 05 22:42:01 2017 +0200 @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -141,8 +141,6 @@ # jdk_io -java/io/pathNames/GeneralWin32.java 8156595 windows-all - ############################################################################ # jdk_management @@ -203,8 +201,6 @@ sun/rmi/rmic/newrmic/equivalence/run.sh 8145980 generic-all -java/rmi/registry/readTest/readTest.sh 7146543 generic-all - ############################################################################ # jdk_security @@ -262,6 +258,8 @@ tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java 8169971 windows-x64 +tools/jmod/JmodTest.java 8172870 windows-all + ############################################################################ # jdk_jdi diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -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. + */ + +/* + * @test + * @bug 8171949 + * @summary Tests that bitwise mask is set and state listener is notified during state transition. + * @author Dmitry Markov + * @library ../../regtesthelpers + * @build Util + * @run main NormalToIconifiedTest + */ + +import java.awt.Frame; +import java.awt.Robot; +import java.awt.event.WindowEvent; +import java.awt.event.WindowStateListener; +import java.util.concurrent.atomic.AtomicBoolean; + +import test.java.awt.regtesthelpers.Util; + +public class NormalToIconifiedTest { + private static final AtomicBoolean listenerNotified = new AtomicBoolean(false); + + public static void main(String[] args) { + Robot robot = Util.createRobot(); + + Frame testFrame = new Frame("Test Frame"); + testFrame.setSize(200, 200); + testFrame.addWindowStateListener(new WindowStateListener() { + @Override + public void windowStateChanged(WindowEvent e) { + listenerNotified.set(true); + synchronized (listenerNotified) { + listenerNotified.notifyAll(); + } + } + }); + testFrame.setVisible(true); + + Frame mainFrame = new Frame("Main Frame"); + mainFrame.setSize(200, 200); + mainFrame.setLocationRelativeTo(null); + mainFrame.setVisible(true); + + Util.waitForIdle(robot); + + try { + Util.clickOnComp(mainFrame, robot); + Util.waitForIdle(robot); + + // NORMAL -> ICONIFIED + listenerNotified.set(false); + testFrame.setExtendedState(Frame.ICONIFIED); + Util.waitForIdle(robot); + + Util.waitForCondition(listenerNotified, 2000); + if (!listenerNotified.get()) { + throw new RuntimeException("Test FAILED! Window state listener was not notified during NORMAL to" + + "ICONIFIED transition"); + } + if (testFrame.getExtendedState() != Frame.ICONIFIED) { + throw new RuntimeException("Test FAILED! Frame is not in ICONIFIED state"); + } + + // ICONIFIED -> NORMAL + listenerNotified.set(false); + testFrame.setExtendedState(Frame.NORMAL); + Util.waitForIdle(robot); + + Util.waitForCondition(listenerNotified, 2000); + if (!listenerNotified.get()) { + throw new RuntimeException("Test FAILED! Window state listener was not notified during ICONIFIED to" + + "NORMAL transition"); + } + if (testFrame.getExtendedState() != Frame.NORMAL) { + throw new RuntimeException("Test FAILED! Frame is not in NORMAL state"); + } + } finally { + testFrame.dispose(); + mainFrame.dispose(); + } + } +} + diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/Frame/ObscuredFrame/ObscuredFrameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Frame/ObscuredFrame/ObscuredFrameTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,70 @@ +/* + * 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 8171952 + * @summary Tests that getMousePosition() returns null for obscured component. + * @author Dmitry Markov + * @library ../../regtesthelpers + * @build Util + * @run main ObscuredFrameTest + */ + +import java.awt.*; + +import test.java.awt.regtesthelpers.Util; + +public class ObscuredFrameTest { + public static void main(String[] args) { + Robot robot = Util.createRobot(); + + Frame frame = new Frame("Obscured Frame"); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + Button button = new Button("Button"); + frame.add(button); + + Dialog dialog = new Dialog(frame, "Visible Dialog", false); + dialog.setSize(200, 200); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); + + frame.setVisible(true); + + Util.waitForIdle(robot); + + Util.pointOnComp(button, robot); + Util.waitForIdle(robot); + + try { + if (button.getMousePosition() != null) { + throw new RuntimeException("Test Failed! Mouse position is not null for obscured component."); + } + } finally { + frame.dispose(); + dialog.dispose(); + } + } +} + diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java --- a/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -23,7 +23,7 @@ /* @test @key headful - @bug 8166897 + @bug 8166897 8167652 @summary Some font overlap in the Optionpane dialog. @run main ChangeWindowResizabiltyTest */ @@ -34,41 +34,75 @@ import java.awt.Frame; import java.awt.Panel; import java.awt.Robot; +import java.awt.Point; 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); + dialog.setLocation(100, 100); Component panel = new Panel(); panel.setPreferredSize(new Dimension(200, 100)); dialog.add(panel); dialog.pack(); dialog.setVisible(true); + robot.waitForIdle(); + robot.delay(200); + + Point frameLoc = dialog.getLocationOnScreen(); + Point contentLoc = panel.getLocationOnScreen(); + + System.out.println("Decor location " + frameLoc); + System.out.println("Content location " + contentLoc); dialog.setResizable(false); robot.waitForIdle(); robot.delay(200); - System.out.println(panel.getLocationOnScreen()); - System.out.println(dialog.getLocationOnScreen()); + Point l = dialog.getLocationOnScreen(); + if (!l.equals(frameLoc)) { + dialog.dispose(); + throw new RuntimeException("Decorated frame location moved " + + "after setResizable(false)" + l); + } + + l = panel.getLocationOnScreen(); + if (!l.equals(contentLoc)) { + dialog.dispose(); + throw new RuntimeException("Content location moved after " + + "setResizable(false)" + l); + } + if (panel.getLocationOnScreen().y < - dialog.getLocationOnScreen().y + dialog.getInsets().top) { + dialog.getLocationOnScreen().y + dialog.getInsets().top) { dialog.dispose(); throw new RuntimeException( - "Wrong content position after setResizable(false)"); + "Wrong content position after setResizable(false)"); } dialog.setResizable(true); robot.waitForIdle(); robot.delay(200); - System.out.println(panel.getLocationOnScreen()); - System.out.println(dialog.getLocationOnScreen()); + + l = dialog.getLocationOnScreen(); + if (!l.equals(frameLoc)) { + dialog.dispose(); + throw new RuntimeException("Decorated frame location moved " + + "after setResizable(true)" + l); + } + + l = panel.getLocationOnScreen(); + if (!l.equals(contentLoc)) { + dialog.dispose(); + throw new RuntimeException("Content location moved after " + + "setResizable(true)" + l); + } if (panel.getLocationOnScreen().y < - dialog.getLocationOnScreen().y + dialog.getInsets().top) { + dialog.getLocationOnScreen().y + dialog.getInsets().top) { dialog.dispose(); throw new RuntimeException( - "Wrong content position after setResizable(true)"); + "Wrong content position after setResizable(true)"); } dialog.dispose(); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java --- a/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -22,7 +22,6 @@ */ import sun.awt.image.MultiResolutionToolkitImage; -import sun.java2d.SunGraphics2D; import javax.swing.*; import java.awt.*; @@ -37,7 +36,6 @@ * @summary [macosx] Drag image of TransferHandler does not honor * MultiResolutionImage * @modules java.desktop/sun.awt.image - * java.desktop/sun.java2d * @run main MultiResolutionDragImageTest TEST_DRAG */ public class MultiResolutionDragImageTest { @@ -126,30 +124,11 @@ return Math.abs(n - m) <= 50; } - private static float getScaleFactor() { - - final Dialog dialog = new Dialog((Window) null); - dialog.setSize(100, 100); - dialog.setModal(true); - final float[] scaleFactors = new float[1]; - Panel panel = new Panel() { - - @Override - public void paint(Graphics g) { - float scaleFactor = 1; - if (g instanceof SunGraphics2D) { - scaleFactor = ((SunGraphics2D) g).surfaceData.getDefaultScale(); - } - scaleFactors[0] = scaleFactor; - dialog.setVisible(false); - } - }; - - dialog.add(panel); - dialog.setVisible(true); - dialog.dispose(); - - return scaleFactors[0]; + static float getScaleFactor() { + return (float) GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(). + getDefaultTransform().getScaleX(); } private static Image createMultiResolutionImage() { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java --- a/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* @test - @bug 4328745 5090704 + @bug 4328745 5090704 8166111 @summary exercise getLayoutFlags, getGlyphCharIndex, getGlyphCharIndices */ @@ -82,7 +82,7 @@ test("latin", latinGV, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); test("hebrew", hebrewGV, GlyphVector.FLAG_RUN_RTL | GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); - test("arabic", arabicGV, GlyphVector.FLAG_RUN_RTL | + test("arabic", arabicGV, GlyphVector.FLAG_COMPLEX_GLYPHS | GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); test("hindi", hindiGV, GlyphVector.FLAG_COMPLEX_GLYPHS | GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/image/Raster/TestChildRasterOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/image/Raster/TestChildRasterOp.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8130737 8172559 + * @summary test no exception rasterop for child raster with non-zero offset + */ + +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferUShort; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class TestChildRasterOp { + + private static AffineTransform at = new AffineTransform(); + private static final AffineTransformOp rop = + new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + private static int[] offsets = {0}; + + public static void main(String[] args) { + testByteRaster(); + testShortRaster(); + testIntRaster(); + } + + private static void testByteRaster() { + WritableRaster srcRaster, dstRaster; + + byte[] pixels = + { 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44 }; + + DataBuffer db = new DataBufferByte(pixels, pixels.length); + srcRaster = + Raster.createInterleavedRaster(db, 4, 4, 4, 1, offsets, null); + srcRaster = srcRaster.createWritableChild(1, 1, 3, 3, 0, 0, null); + dstRaster = rop.filter(srcRaster, null); + } + + private static void testShortRaster() { + WritableRaster srcRaster, dstRaster; + + short[] pixels = + { 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44 }; + + DataBuffer db = new DataBufferUShort(pixels, pixels.length); + srcRaster = + Raster.createInterleavedRaster(db, 4, 4, 4, 1, offsets, null); + srcRaster = srcRaster.createWritableChild(1, 1, 3, 3, 0, 0, null); + dstRaster = rop.filter(srcRaster, null); + } + + private static void testIntRaster() { + WritableRaster srcRaster, dstRaster; + + int[] pixels = + { 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44 }; + + DataBuffer db = new DataBufferInt(pixels, pixels.length); + srcRaster = + Raster.createPackedRaster(db, 4, 4, 4, offsets, null); + srcRaster = srcRaster.createWritableChild(1, 1, 3, 3, 0, 0, null); + dstRaster = rop.filter(srcRaster, null); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java --- a/jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java Wed Jul 05 22:42:01 2017 +0200 @@ -24,16 +24,28 @@ /* * @test * @key headful - * @bug 7108598 + * @bug 7108598 8172009 * @summary Container.paint/KeyboardFocusManager.clearMostRecentFocusOwner methods deadlock * @library ../../regtesthelpers * @author Oleg Pekhovskiy * @build Util - * @run main/timeout=20 PaintSetEnabledDeadlock + * @run main PaintSetEnabledDeadlock */ -import java.awt.*; -import java.awt.event.*; +import java.awt.Button; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import test.java.awt.regtesthelpers.Util; public class PaintSetEnabledDeadlock extends Frame { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/print/PrinterJob/BannerTest.java --- a/jdk/test/java/awt/print/PrinterJob/BannerTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/awt/print/PrinterJob/BannerTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -22,7 +22,7 @@ */ /* * @test - * @bug 6575247 + * @bug 6575247 8170579 * @summary Verifies if Banner page is printed * @requires (os.family == "linux" | os.family == "solaris") * @run main/manual BannerTest @@ -39,6 +39,9 @@ import static java.awt.print.Printable.PAGE_EXISTS; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; +import javax.print.PrintService; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.SheetCollate; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JPanel; @@ -50,8 +53,18 @@ private static Thread mainThread; private static boolean testPassed; private static boolean testGeneratedInterrupt; + private static volatile PrinterJob job; public static void main(String[] args) throws Exception { + job = PrinterJob.getPrinterJob(); + PrintService prtSrv = job.getPrintService(); + if (job.getPrintService() == null) { + System.out.println("No printers. Test cannot continue"); + return; + } + if (!prtSrv.isAttributeCategorySupported(JobSheets.class)) { + return; + } SwingUtilities.invokeAndWait(() -> { doTest(BannerTest::printTest); }); @@ -69,11 +82,6 @@ } private static void printTest() { - PrinterJob job = PrinterJob.getPrinterJob(); - if (job.getPrintService() == null) { - System.out.println("No printers. Test cannot continue"); - return; - } job.setPrintable(new BannerTest()); if(job.printDialog()) { try { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java --- a/jdk/test/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java Wed Jul 05 22:42:01 2017 +0200 @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8165947 + * @bug 8165947 8170579 * @summary Verifies System default banner page option is honoured by jdk * @requires (os.family == "linux" | os.family == "solaris") * @run main/manual TestCheckSystemDefaultBannerOption @@ -38,6 +38,7 @@ import static java.awt.print.Printable.PAGE_EXISTS; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; +import javax.print.PrintService; import javax.print.attribute.standard.JobSheets; import javax.swing.JButton; import javax.swing.JDialog; @@ -56,10 +57,15 @@ public static void main (String[] args) throws Exception { job = PrinterJob.getPrinterJob(); - if (job.getPrintService() == null) { + PrintService prtSrv = job.getPrintService(); + if (prtSrv == null) { System.out.println("No printers. Test cannot continue"); return; } + // do not run the test if JobSheet category is not supported + if (!prtSrv.isAttributeCategorySupported(JobSheets.class)) { + return; + } // check system default banner option and let user know what to expect JobSheets js = (JobSheets)job.getPrintService(). getDefaultAttributeValue(JobSheets.class); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/io/File/WinDirRelative.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/File/WinDirRelative.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8153250 + * @summary Tests that files are correctly listed for a directory-relative path + * @requires (os.family == "windows") + */ +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class WinDirRelative { + private static final char COLON = ':'; + private static final String BASENAME = "TestFile_"; + private static final String EXTENSION = ".txt"; + private static final int NUM_FILES = 10; + + private static boolean isLetter(char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + } + + public static void main(String[] args) throws Throwable { + // Get the working directory which is also the default + // directory for the current drive. + String userDir = System.getProperty("user.dir"); + + // Test only if a leading drive letter is found + if (isLetter(userDir.charAt(0)) && userDir.charAt(1) == COLON) { + // Create some empty files + List filenames = new ArrayList(NUM_FILES); + for (int i = 0; i < NUM_FILES; i++) { + String filename = BASENAME + i + EXTENSION; + filenames.add(filename); + File f = new File(filename); + f.createNewFile(); + f.deleteOnExit(); + System.out.printf("Created %s (%s)%n", filename, + f.getAbsolutePath()); + } + + // List files and verify that the ones with recognized names exist. + String prefix = userDir.substring(0, 2); + File p = new File(prefix); + int failures = 0; + int successes = 0; + for (File f : p.listFiles()) { + if (f.getName().toString().startsWith(BASENAME)) { + if (!f.exists()) { + System.err.printf("%s (%s) does not exist%n", f, + f.getAbsolutePath()); + failures++; + } else { + successes++; + } + } + } + + // Fail if there was an existence test failure or if not + // enough of the created files were found + boolean testFailed = false; + if (failures > 0) { + System.err.println("Existence check failed"); + testFailed = true; + } + if (successes != NUM_FILES) { + System.err.println("Count check failed"); + testFailed = true; + } + if (testFailed) { + throw new RuntimeException("Test failed"); + } + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/io/File/createTempFile/Patterns.java --- a/jdk/test/java/io/File/createTempFile/Patterns.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/io/File/createTempFile/Patterns.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +22,7 @@ */ /* @test - @bug 4152178 + @bug 4152178 8152272 @summary Check various temp-file prefix/suffix cases */ import java.io.File; @@ -66,6 +66,7 @@ cky("xxx", ""); cky("xxx", "y"); cky("xxx", ".y"); + cky("xyz", "Directory" + System.getProperty("file.separator")); } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/io/pathNames/General.java --- a/jdk/test/java/io/pathNames/General.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/io/pathNames/General.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ private static int gensymCounter = 0; protected static final String userDir = System.getProperty("user.dir"); + protected static final String workSubDir = "tmp"; protected static String baseDir = null; protected static String relative = null; @@ -60,7 +61,10 @@ * direct or indirect calling) in a whole test. */ protected static void initTestData(int depth) throws IOException { - File parent = new File(userDir); + File parent = new File(userDir + File.separator + workSubDir); + if (!parent.mkdir()) { + throw new IOException("Fail to create directory: " + parent); + } for (int i = 0; i < depth; i++) { File tmp = new File(parent, gensym()); tmp.createNewFile(); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/io/pathNames/GeneralWin32.java --- a/jdk/test/java/io/pathNames/GeneralWin32.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/io/pathNames/GeneralWin32.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,8 @@ private static void checkCaseLookup() throws IOException { /* Use long names here to avoid 8.3 format, which Samba servers often force to lowercase */ - File d = new File("XyZzY0123", "FOO_bar_BAZ"); + File r = new File (workSubDir, "XyZzY0123"); + File d = new File(r, "FOO_bar_BAZ"); File f = new File(d, "GLORPified"); if (!f.exists()) { if (!d.exists()) { @@ -74,9 +75,9 @@ case of filenames, rather than just using the input case */ File y = new File(userDir, f.getPath()); String ans = y.getPath(); - check(ans, "XyZzY0123\\FOO_bar_BAZ\\GLORPified"); - check(ans, "xyzzy0123\\foo_bar_baz\\glorpified"); - check(ans, "XYZZY0123\\FOO_BAR_BAZ\\GLORPIFIED"); + check(ans, workSubDir + File.separator + "XyZzY0123\\FOO_bar_BAZ\\GLORPified"); + check(ans, workSubDir + File.separator + "xyzzy0123\\foo_bar_baz\\glorpified"); + check(ans, workSubDir + File.separator + "XYZZY0123\\FOO_BAR_BAZ\\GLORPIFIED"); } private static void checkWild(File f) throws Exception { @@ -125,20 +126,19 @@ throw new RuntimeException("Can't find an active drive"); } - private static void checkDrive(int depth, char drive, boolean exists) + private static void checkDrive(int depth, String drive, boolean exists) throws Exception { - String d = drive + ":"; - File df = new File(d); - String ans = exists ? df.getAbsolutePath() : d; + File df = new File(drive); + String ans = exists ? df.getAbsolutePath() : drive; if (!ans.endsWith("\\")) ans = ans + "\\"; - checkNames(depth, false, ans, d); + checkNames(depth, false, ans, drive); } private static void checkDrivePaths(int depth) throws Exception { - checkDrive(depth, findActiveDrive(), true); - checkDrive(depth, findInactiveDrive(), false); + checkDrive(depth, findActiveDrive() + ":" + workSubDir + File.separator, true); + checkDrive(depth, findInactiveDrive() + ":", false); } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/net/URLConnection/SetDefaultUseCaches.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/URLConnection/SetDefaultUseCaches.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 8163449 + * @summary Allow per protocol setting for URLConnection defaultUseCaches + * @run main/othervm SetDefaultUseCaches + */ + +import java.net.*; +import java.io.*; + +public class SetDefaultUseCaches { + static void testAssert(boolean value, boolean comparator) { + if (value != comparator) { + System.err.println("Expected " + comparator + " Got " + value); + throw new RuntimeException("Test failed:"); + } else + System.err.println("OK"); + } + + public static void main(String s[]) throws Exception { + URL url = new URL("http://www.foo.com/"); + URL url1 = new URL("file:///a/b.txt"); + + // check default default is true + URLConnection urlc = url.openConnection(); + testAssert(urlc.getDefaultUseCaches(), true); + + // set default for http to false and check + URLConnection.setDefaultUseCaches("HTTP", false); + + urlc = url.openConnection(); + testAssert(urlc.getDefaultUseCaches(), true); + testAssert(urlc.getUseCaches(), false); + testAssert(URLConnection.getDefaultUseCaches("http"), false); + + URLConnection urlc1 = url1.openConnection(); + testAssert(urlc1.getDefaultUseCaches(), true); + + // set default default to false and check other values the same + urlc.setDefaultUseCaches(false); + urlc1.setDefaultUseCaches("fiLe", true); + testAssert(urlc1.getDefaultUseCaches(), false); + testAssert(URLConnection.getDefaultUseCaches("fiLE"), true); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java --- a/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary JavaVM RMID TestSecurityManager + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider RegistryVM RMIRegistryRunner + * TestSecurityManager * @run main/othervm AltSecurityManager */ @@ -44,7 +46,6 @@ * if registry and rmid take too long to exit. */ public class AltSecurityManager implements Runnable { - private final int regPort; // variable to hold registry and rmid children static JavaVM vm = null; @@ -57,31 +58,34 @@ private static final long TIME_OUT = (long)(15000 * TestLibrary.getTimeoutFactor()); - public AltSecurityManager(int port) { - if (port <= 0) { - TestLibrary.bomb("Port must be greater than 0."); - } - - this.regPort = port; - } - public void run() { try { if (utilityToStart.equals(REGISTRY_IMPL)) { - vm = new JavaVM(utilityToStart, - " -Djava.security.manager=TestSecurityManager", - Integer.toString(regPort)); + vm = RegistryVM.createRegistryVMWithRunner( + "RMIRegistryRunner", + "-Djava.security.manager=TestSecurityManager"); } else if (utilityToStart.contains(ACTIVATION)) { - vm = new JavaVM(utilityToStart, - " -Djava.security.manager=TestSecurityManager", - "-port " + Integer.toString(regPort)); + vm = RMID.createRMIDOnEphemeralPortWithOptions( + "-Djava.security.manager=TestSecurityManager"); } else { TestLibrary.bomb("Utility to start must be " + REGISTRY_IMPL + " or " + ACTIVATION); } System.err.println("starting " + utilityToStart); - vm.execute(); + try { + vm.start(); + throw new RuntimeException("Expected exception did not occur!"); + } catch (Exception expected) { + int exit = vm.waitFor(); + if (exit != TestSecurityManager.EXIT_VALUE) { + throw new RuntimeException(utilityToStart + + " exit with an unexpected value " + + exit + "."); + } + System.err.format("Success: starting %s exited with status %d%n", + utilityToStart, TestSecurityManager.EXIT_VALUE); + } } catch (Exception e) { TestLibrary.bomb(e); @@ -96,8 +100,7 @@ utilityToStart = utility; try { - int port = TestLibrary.getUnusedRandomPort(); - Thread thread = new Thread(new AltSecurityManager(port)); + Thread thread = new Thread(new AltSecurityManager()); System.err.println("expecting RuntimeException for " + "checkListen in child process"); long start = System.currentTimeMillis(); @@ -116,7 +119,7 @@ " terminated on time"); } } finally { - vm.destroy(); + vm.cleanup(); vm = null; } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/altSecurityManager/TestSecurityManager.java --- a/jdk/test/java/rmi/registry/altSecurityManager/TestSecurityManager.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/registry/altSecurityManager/TestSecurityManager.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +24,8 @@ /**/ public class TestSecurityManager extends SecurityManager { + public static final int EXIT_VALUE = 123; + public TestSecurityManager() { } @@ -36,7 +38,7 @@ // by the main test process to detect that the proper security // manager has been installed in the relevant VMs. // - System.exit(1); + System.exit(EXIT_VALUE); } public void checkExit(int status) { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/altSecurityManager/registry.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/altSecurityManager/registry.security.policy Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,8 @@ +grant { + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; + permission java.util.PropertyPermission "env.class.path", "read"; + permission java.io.FilePermission ".", "read"; + permission java.util.PropertyPermission "user.dir", "read"; + permission java.lang.RuntimePermission "createClassLoader"; + permission java.lang.RuntimePermission "setContextClassLoader"; +}; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/altSecurityManager/rmid.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/altSecurityManager/rmid.security.policy Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,7 @@ +grant { + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; + permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.port", "read"; + permission java.util.PropertyPermission "test.java.rmi.testlibrary.RMIDSelectorProvider.timeout", "read"; + permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept"; +}; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java --- a/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +34,7 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary Dummy + * @build TestLibrary Dummy RegistryVM RMIRegistryRunner * @run main/othervm/policy=security.policy * -Djava.rmi.server.useCodebaseOnly=false ClassPathCodebase */ @@ -48,8 +48,9 @@ public class ClassPathCodebase { - /** wait 10 seconds for the registry process to be ready to call */ - private final static long REGISTRY_WAIT = 15000; + /** wait dozens of seconds for the registry process to be ready to call */ + private static final long REGISTRY_WAIT = + (long)(10000 * TestLibrary.getTimeoutFactor()); private final static String dummyClassName = "Dummy"; @@ -64,7 +65,7 @@ TestLibrary.suggestSecurityManager("java.lang.SecurityManager"); - Process rmiregistry = null; + RegistryVM rmiregistry = null; try { /* @@ -82,27 +83,13 @@ * Spawn an rmiregistry in the "import" codebase directory. */ File rmiregistryDir = - new File(System.getProperty("user.dir", "."), importCodebase); - - String rmiregistryCommand = - System.getProperty("java.home") + File.separator + - "bin" + File.separator + "rmiregistry"; - - int port = TestLibrary.getUnusedRandomPort(); - String cmdarray[] = new String[] { - rmiregistryCommand, - "-J-Denv.class.path=.", - "-J-Djava.rmi.server.codebase=" + exportCodebaseURL, - Integer.toString(port) }; - - System.err.println("\nCommand used to spawn rmiregistry process:"); - System.err.println("\t" + Arrays.asList(cmdarray).toString()); - - rmiregistry = Runtime.getRuntime().exec(cmdarray, null, rmiregistryDir); - - // pipe rmiregistry output to our output, for debugging failures - StreamPipe.plugTogether(rmiregistry.getInputStream(), System.err); - StreamPipe.plugTogether(rmiregistry.getErrorStream(), System.err); + new File(System.getProperty("user.dir", "."), importCodebase); + rmiregistry = RegistryVM.createRegistryVMWithRunner("RMIRegistryRunner", + " -Denv.class.path=." + + " -Djava.rmi.server.codebase=" + exportCodebaseURL + + " -Duser.dir=" + rmiregistryDir.getAbsolutePath()); + rmiregistry.start(); + int port = rmiregistry.getPort(); /* * Wait for the registry to initialize and be ready to call. @@ -174,7 +161,7 @@ throw new RuntimeException("TEST FAILED: " + e.toString()); } finally { if (rmiregistry != null) { - rmiregistry.destroy(); + rmiregistry.cleanup(); } } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/classPathCodebase/registry.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/classPathCodebase/registry.security.policy Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,18 @@ +/* + * security policy used by the registry process started by RegistryVM. + */ + +grant { + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; + permission java.util.PropertyPermission "env.class.path", "read"; + permission java.io.FilePermission ".", "read"; + permission java.util.PropertyPermission "user.dir", "read"; + permission java.lang.RuntimePermission "createClassLoader"; + permission java.lang.RuntimePermission "setContextClassLoader"; + permission java.io.FilePermission ".-Djava.rmi.server.codebase=file", "read"; + permission java.io.FilePermission ".${/}-", "read"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp"; + permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept"; +}; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/classPathCodebase/security.policy --- a/jdk/test/java/rmi/registry/classPathCodebase/security.policy Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/registry/classPathCodebase/security.policy Wed Jul 05 22:42:01 2017 +0200 @@ -18,6 +18,12 @@ // test needs to use java to exec an rmiregistry permission java.io.FilePermission "${java.home}${/}bin${/}-", "execute"; - // test needs to communicate with this its registry + // test needs to communicate with its registry permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.util.PropertyPermission "java.security.policy", "read"; + permission java.util.PropertyPermission "java.security.manager", "read"; + + // used by TestLibrary to determine extra commandline properties + permission java.io.FilePermission "..${/}..${/}test.props", "read"; }; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/readTest/CodebaseTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/CodebaseTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7102369 7094468 7100592 + * @modules java.rmi/sun.rmi.registry + * java.rmi/sun.rmi.server + * java.rmi/sun.rmi.transport + * java.rmi/sun.rmi.transport.tcp + * @library ../../testlibrary + * @build TestLibrary RMIRegistryRunner RegistryVM JavaVM testPkg.* RegistryLookup + * @summary remove java.rmi.server.codebase property parsing from registyimpl + * @run main/othervm CodebaseTest +*/ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.rmi.registry.Registry; +import java.rmi.registry.LocateRegistry; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; + +public class CodebaseTest { + + public static void main(String args[]) throws Exception { + RegistryVM rmiregistry = null; + JavaVM client = null; + try { + File src = new File(System.getProperty("test.classes", "."), "testPkg"); + File dest = new File(System.getProperty("user.dir", "."), "testPkg"); + Files.move(src.toPath(), dest.toPath(), + StandardCopyOption.REPLACE_EXISTING); + + File rmiregistryDir = + new File(System.getProperty("user.dir", "."), "rmi_tmp"); + rmiregistryDir.mkdirs(); + rmiregistry = RegistryVM.createRegistryVMWithRunner( + "RMIRegistryRunner", + " -Djava.rmi.server.useCodebaseOnly=false" + + " -Duser.dir=" + rmiregistryDir.getAbsolutePath()); + rmiregistry.start(); + int port = rmiregistry.getPort(); + + File srcReadTest = new File(System.getProperty("test.classes", "."), + "RegistryLookup.class"); + File destReadTest = new File(System.getProperty("user.dir", "."), + "RegistryLookup.class"); + Files.move(srcReadTest.toPath(), destReadTest.toPath(), + StandardCopyOption.REPLACE_EXISTING); + + File codebase = new File(System.getProperty("user.dir", ".")); + client = new JavaVM("RegistryLookup", + " -Djava.rmi.server.codebase=" + codebase.toURI().toURL() + + " -cp ." + File.pathSeparator + System.getProperty("test.class.path"), + Integer.toString(port)); + int exit = client.execute(); + if (exit == RegistryLookup.EXIT_FAIL) { + throw new RuntimeException("Test Fails"); + } + } finally { + if (rmiregistry != null) { + rmiregistry.cleanup(); + } + if (client != null) { + client.cleanup(); + } + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/readTest/RegistryLookup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/RegistryLookup.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.rmi.registry.Registry; +import java.rmi.registry.LocateRegistry; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; + +public class RegistryLookup { + public static final int EXIT_FAIL = 1; + + public static void main(String args[]) throws Exception { + Registry registry = null; + int exit = 0; + try { + int port = Integer.valueOf(args[0]); + + testPkg.Server obj = new testPkg.Server(); + testPkg.Hello stub = + (testPkg.Hello) UnicastRemoteObject.exportObject(obj, 0); + // Bind the remote object's stub in the registry + registry = LocateRegistry.getRegistry(port); + registry.bind("Hello", stub); + System.err.println("Server ready"); + + testPkg.Client client = new testPkg.Client(port); + String testStubReturn = client.testStub(); + if(!testStubReturn.equals(obj.hello)) { + throw new RuntimeException("Test Fails : " + + "unexpected string from stub call"); + } + registry.unbind("Hello"); + System.out.println("Test passed"); + } catch (Exception ex) { + exit = EXIT_FAIL; + ex.printStackTrace(); + } + // need to exit explicitly, and parent process uses exit value + // to tell if the test passed. + System.exit(exit); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/readTest/readTest.java --- a/jdk/test/java/rmi/registry/readTest/readTest.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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.rmi.registry.Registry; -import java.rmi.registry.LocateRegistry; -import java.rmi.RemoteException; -import java.rmi.server.UnicastRemoteObject; - -public class readTest { - - public static void main(String args[]) throws Exception { - try { - testPkg.Server obj = new testPkg.Server(); - testPkg.Hello stub = (testPkg.Hello) UnicastRemoteObject.exportObject(obj, 0); - // Bind the remote object's stub in the registry - Registry registry = - LocateRegistry.getRegistry(TestLibrary.READTEST_REGISTRY_PORT); - registry.bind("Hello", stub); - - System.err.println("Server ready"); - - // now, let's test client - testPkg.Client client = - new testPkg.Client(TestLibrary.READTEST_REGISTRY_PORT); - String testStubReturn = client.testStub(); - if(!testStubReturn.equals(obj.hello)) { - throw new RuntimeException("Test Fails : unexpected string from stub call"); - } else { - System.out.println("Test passed"); - } - registry.unbind("Hello"); - - } catch (Exception e) { - System.err.println("Server exception: " + e.toString()); - e.printStackTrace(); - } - - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/readTest/readTest.sh --- a/jdk/test/java/rmi/registry/readTest/readTest.sh Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -# -# Copyright (c) 2011, 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. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 7102369 7094468 7100592 -# @modules java.rmi/sun.rmi.registry -# java.rmi/sun.rmi.server -# java.rmi/sun.rmi.transport -# java.rmi/sun.rmi.transport.tcp -# @library ../../testlibrary -# @build TestLibrary -# @summary remove java.rmi.server.codebase property parsing from registyimpl -# @run shell readTest.sh -# @key intermittent - -OS=`uname -s` -VER=`uname -r` -ARGS="" -REGARGS="" - -case "$OS" in - SunOS | Linux | Darwin | AIX ) - PS=":" - FS="/" - CHMOD="${FS}bin${FS}chmod" - FILEURL="file:" - ;; - Windows* ) - PS=";" - FS="\\" - CHMOD="chmod" - FILEURL="file:/" - if [ "$VER" -eq "5" ]; then - ARGS="-Djdk.net.ephemeralPortRange.low=1024 -Djdk.net.ephemeralPortRange.high=65000" - REGARGS="-J-Djdk.net.ephemeralPortRange.low=1024 -J-Djdk.net.ephemeralPortRange.high=65000" - fi - ;; - CYGWIN* ) - PS=";" - FS="/" - CHMOD="chmod" - FILEURL="file:/" - if [ "$VER" -eq "5" ]; then - ARGS="-Djdk.net.ephemeralPortRange.low=1024 -Djdk.net.ephemeralPortRange.high=65000" - REGARGS="-J-Djdk.net.ephemeralPortRange.low=1024 -J-Djdk.net.ephemeralPortRange.high=65000" - fi - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -TEST_CLASSPATH=.$PS${TESTCLASSPATH:-$TESTCLASSES} -cp -r ${TESTSRC}${FS}* . -${CHMOD} -R u+w * -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} testPkg${FS}*java -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -cp $TEST_CLASSPATH readTest.java - -mkdir rmi_tmp -RMIREG_OUT=rmi.out -#start rmiregistry without any local classes on classpath -cd rmi_tmp -# NOTE: This RMI Registry port must match TestLibrary.READTEST_REGISTRY_PORT -${TESTJAVA}${FS}bin${FS}rmiregistry ${REGARGS} -J-Djava.rmi.server.useCodebaseOnly=false \ - ${TESTTOOLVMOPTS} 60005 > ..${FS}${RMIREG_OUT} 2>&1 & -RMIREG_PID=$! -# allow some time to start -sleep 3 -cd .. - -case "$OS" in - CYGWIN* ) - CODEBASE=`cygpath -w $PWD` - ;; - * ) - CODEBASE=`pwd` - ;; -esac -# trailing / after code base is important for rmi codebase property. -TESTVMOPTS="${TESTVMOPTS} \ - --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED \ - --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED \ - --add-exports java.rmi/sun.rmi.transport=ALL-UNNAMED \ - --add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp $TEST_CLASSPATH ${ARGS} -Djava.rmi.server.codebase=${FILEURL}$CODEBASE/ readTest > OUT.TXT 2>&1 & -TEST_PID=$! -#bulk of testcase - let it run for a while -sleep 5 - -#we're done, kill processes first -kill -9 ${RMIREG_PID} ${TEST_PID} -sleep 3 - -echo "Test output : " - -cat OUT.TXT -echo "==============" -echo "rmiregistry output : " -cat ${RMIREG_OUT} -echo "==============" - -grep "Server ready" OUT.TXT -result1=$? -grep "Test passed" OUT.TXT -result2=$? - -if [ $result1 -eq 0 -a $result2 -eq 0 ] -then - echo "Passed" - exitCode=0; -else - echo "Failed" - exitCode=1 -fi -rm -rf OUT.TXT ${RMIREG_OUT} rmi_tmp -exit ${exitCode} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/readTest/registry.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/registry.security.policy Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,12 @@ +grant { + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry"; + permission java.util.PropertyPermission "env.class.path", "read"; + permission java.io.FilePermission ".", "read"; + permission java.util.PropertyPermission "user.dir", "read"; + permission java.lang.RuntimePermission "createClassLoader"; + permission java.lang.RuntimePermission "setContextClassLoader"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp"; + permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept"; +}; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/registry/reexport/Reexport.java --- a/jdk/test/java/rmi/registry/reexport/Reexport.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/registry/reexport/Reexport.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary REGISTRY RegistryRunner + * @build TestLibrary RegistryVM RegistryRunner * @run main/othervm Reexport */ @@ -114,7 +114,7 @@ public static void makeRegistry() { try { - subreg = REGISTRY.createREGISTRY(); + subreg = RegistryVM.createRegistryVM(); subreg.start(); port = subreg.getPort(); System.out.println("Starting registry on port " + port); @@ -125,12 +125,12 @@ } } - private static REGISTRY subreg = null; + private static RegistryVM subreg = null; private static int port = -1; public static void killRegistry() { if (subreg != null) { - subreg.shutdown(); + subreg.cleanup(); subreg = null; } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/JavaVM.java --- a/jdk/test/java/rmi/testlibrary/JavaVM.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/testlibrary/JavaVM.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -230,6 +230,22 @@ } /** + * Return exit value for vm process. + * @return exit value for vm process + * @throws IllegalThreadStateException if the vm process has not yet terminated + */ + public int exitValue() { + return vm.exitValue(); + } + + /** + * Destroy the vm process, and do necessary cleanup. + */ + public void cleanup() { + destroy(); + } + + /** * Destroys the VM, waits for it to terminate, and returns * its exit status. * diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/REGISTRY.java --- a/jdk/test/java/rmi/testlibrary/REGISTRY.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +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. - */ - -import java.io.OutputStream; -import java.io.IOException; - -/** - * Class to run and control rmiregistry in a sub-process. - * - * We can't kill a registry if we have too-close control - * over it. We must make it in a subprocess, and then kill the - * subprocess when it has served our needs. - */ -public class REGISTRY extends JavaVM { - - private static final double START_TIMEOUT = - 20_000 * TestLibrary.getTimeoutFactor(); - private static final String DEFAULT_RUNNER = "RegistryRunner"; - - private int port = -1; - - private REGISTRY(String runner, OutputStream out, OutputStream err, - String options, int port) { - super(runner, options, Integer.toString(port), out, err); - try { - Class runnerClass = Class.forName(runner); - if (!RegistryRunner.class.isAssignableFrom(runnerClass)) { - throw new RuntimeException("runner class must be RegistryRunner" - + " or its sub class"); - } - } catch (ClassNotFoundException ex) { - throw new RuntimeException(ex); - } - this.port = port; - } - - public static REGISTRY createREGISTRY() { - return createREGISTRYWithRunner(DEFAULT_RUNNER, System.out, System.err, "", 0); - } - - public static REGISTRY createREGISTRY(OutputStream out, OutputStream err, - String options, int port) { - return createREGISTRYWithRunner(DEFAULT_RUNNER, out, err, options, port); - } - - public static REGISTRY createREGISTRYWithRunner(String runner, String options) { - return createREGISTRYWithRunner(runner, System.out, System.err, options, 0); - } - - public static REGISTRY createREGISTRYWithRunner(String runner, OutputStream out, - OutputStream err, String options, int port) { - options += " --add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED" - + " --add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED" - + " --add-exports=java.rmi/sun.rmi.transport=ALL-UNNAMED" - + " --add-exports=java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"; - REGISTRY reg = new REGISTRY(runner, out, err, options, port); - return reg; - } - - /** - * Starts the registry in a sub-process and waits up to - * the given timeout period to confirm that it's running, - * and get the port where it's running. - */ - public void start() throws IOException { - super.start(); - long startTime = System.currentTimeMillis(); - long deadline = TestLibrary.computeDeadline(startTime, (long)START_TIMEOUT); - while (true) { - try { - Thread.sleep(1000); - } catch (InterruptedException ignore) { } - - String output = outputStream.ba.toString(); - port = RegistryRunner.getRegistryPort(output); - if (port != -1) { - break; - } - if (System.currentTimeMillis() > deadline) { - TestLibrary.bomb("Failed to start registry, giving up after " + - (System.currentTimeMillis() - startTime) + "ms.", null); - } - } - } - - /** - * Shuts down the registry. - */ - public void shutdown() { - RegistryRunner.requestExit(port); - } - - /** - * Gets the port where the registry is serving. - */ - public int getPort() { - return port; - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/RMID.java --- a/jdk/test/java/rmi/testlibrary/RMID.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/testlibrary/RMID.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,18 +140,6 @@ } private static String makeArgs(boolean includePortArg, int port) { - String propagateManager = null; - - // rmid will run with a security manager set, but no policy - // file - it should not need one. - if (System.getSecurityManager() == null) { - propagateManager = MANAGER_OPTION + - TestParams.defaultSecurityManager; - } else { - propagateManager = MANAGER_OPTION + - System.getSecurityManager().getClass().getName(); - } - // getAbsolutePath requires permission to read user.dir String args = " -log " + (new File(LOGDIR, log)).getAbsolutePath(); @@ -210,7 +198,30 @@ boolean debugExec, boolean includePortArg, int port) { + return createRMIDWithOptions(out, err, debugExec, includePortArg, port, ""); + } + + /** + * Create a RMID on a specified port capturing stdout and stderr + * with additional command line options and whether to print out + * debugging information that is used for spawning activation groups. + * + * @param out the OutputStream where the normal output of the + * rmid subprocess goes + * @param err the OutputStream where the error output of the + * rmid subprocess goes + * @param debugExec whether to print out debugging information + * @param includePortArg whether to include port argument + * @param port the port on which rmid accepts requests + * @param additionalOptions additional command line options + * @return a RMID instance + */ + public static RMID createRMIDWithOptions(OutputStream out, OutputStream err, + boolean debugExec, boolean includePortArg, + int port, String additionalOptions) + { String options = makeOptions(port, debugExec, false); + options += " " + additionalOptions; String args = makeArgs(includePortArg, port); RMID rmid = new RMID("sun.rmi.server.Activation", options, args, out, err, port); @@ -223,6 +234,19 @@ return createRMID(System.out, System.err, true, false, 0); } + /** + * Create a RMID on an ephemeral port capturing stdout and stderr + * with additional command line options. + * + * @param additionalOptions additional command line options + * @return a RMID instance + */ + public static RMID createRMIDOnEphemeralPortWithOptions( + String additionalOptions) { + return createRMIDWithOptions(System.out, System.err, + true, false, 0, additionalOptions); + } + public static RMID createRMIDOnEphemeralPort(OutputStream out, OutputStream err, boolean debugExec) diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/RMIRegistryRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/testlibrary/RMIRegistryRunner.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.rmi.*; +import java.rmi.registry.*; +import java.rmi.server.*; + +/** + * Class to run a rmiregistry whose VM can be told to exit remotely; + * Difference between this class and RegistryRunner is that this class + * simulate rmiregistry closer than RegistryRunner. + */ +public class RMIRegistryRunner extends RegistryRunner +{ + public RMIRegistryRunner() throws RemoteException { + } + + /** + * port 0 means to use ephemeral port to start registry. + * + * @param args command line arguments passed in from main + * @return the port number on which registry accepts requests + */ + protected static int init(String[] args) { + try { + if (args.length == 0) { + System.err.println("Usage: "); + System.exit(0); + } + int port = -1; + port = Integer.parseInt(args[0]); + + // call RegistryImpl.createRegistry to simulate rmiregistry. + registry = sun.rmi.registry.RegistryImpl.createRegistry(port); + if (port == 0) { + port = TestLibrary.getRegistryPort(registry); + } + + // create a remote object to tell this VM to exit + exiter = new RMIRegistryRunner(); + Naming.rebind("rmi://localhost:" + port + + "/RemoteExiter", exiter); + + return port; + } catch (Exception e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + return -1; + } + + public static void main(String[] args) { + int port = init(args); + notify(port); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/RegistryRunner.java --- a/jdk/test/java/rmi/testlibrary/RegistryRunner.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/testlibrary/RegistryRunner.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ /** * Class to run a registry whose VM can be told to exit remotely; using - * the rmiregistry in this fashion makes tests more robust under + * a registry (in a sub-process) in this fashion makes tests more robust under * windows where Process.destroy() seems not to be 100% reliable. */ public class RegistryRunner extends UnicastRemoteObject @@ -38,8 +38,8 @@ private static final String PORT_LABEL_START = "RegistryRunner.port.start:"; private static final String PORT_LABEL_END = ":RegistryRunner.port.end"; - private static Registry registry = null; - private static RemoteExiter exiter = null; + protected static Registry registry = null; + protected static RemoteExiter exiter = null; public RegistryRunner() throws RemoteException { } @@ -72,6 +72,7 @@ } catch (RemoteException re) { } e = null; + } catch (java.net.MalformedURLException mfue) { // will not happen } catch (NotBoundException nbe) { @@ -97,6 +98,9 @@ /** * port 0 means to use ephemeral port to start registry. + * + * @param args command line arguments passed in from main + * @return the port number on which registry accepts requests */ protected static int init(String[] args) { try { @@ -128,13 +132,15 @@ } /** - * REGISTRY.start() will filter the output of registry subprocess, - * when valid port is detected, REGISTRY.start() returns. + * RegistryVM.start() will filter the output of registry subprocess, + * when valid port is detected, RegistryVM.start() returns. * So, for subclass, it's important to call this method after registry * is initialized and necessary remote objects have been bound. + * + * @param port the port on which registry accepts requests */ protected static void notify(int port) { - // this output is important for REGISTRY to get the port + // this output is important for RegistryVM to get the port // where rmiregistry is serving System.out.println(PORT_LABEL_START + port + PORT_LABEL_END); System.out.flush(); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/RegistryVM.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/testlibrary/RegistryVM.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.OutputStream; +import java.io.IOException; + +/** + * Class to run and control registry/rmiregistry in a sub-process. + * The behaviour changes when use different runner, currently + * there are 2 built-in runners, RegistryRunner and RMIRegistryRunner. + * + * We can't kill a registry if we have too-close control + * over it. We must make it in a subprocess, and then kill the + * subprocess when it has served our needs. + */ +public class RegistryVM extends JavaVM { + + private static final double START_TIMEOUT = + 20_000 * TestLibrary.getTimeoutFactor(); + private static final String DEFAULT_RUNNER = "RegistryRunner"; + + private int port = -1; + + private RegistryVM(String runner, OutputStream out, OutputStream err, + String options, int port) { + super(runner, options, Integer.toString(port), out, err); + try { + Class runnerClass = Class.forName(runner); + if (!RegistryRunner.class.isAssignableFrom(runnerClass)) { + throw new RuntimeException("runner class must be RegistryRunner" + + " or its sub class"); + } + } catch (ClassNotFoundException ex) { + throw new RuntimeException(ex); + } + this.port = port; + } + + /** + * Create a RegistryVM instance on an ephemeral port. + * + * @return a RegistryVM instance + */ + public static RegistryVM createRegistryVM() { + return createRegistryVMWithRunner(DEFAULT_RUNNER, System.out, System.err, "", 0); + } + + /** + * Create a RegistryVM instance on an ephemeral port with additional + * command line options. + * + * @param options command line options + * @return a RegistryVM instance + */ + public static RegistryVM createRegistryVM(String options) { + return createRegistryVMWithRunner( + DEFAULT_RUNNER, System.out, System.err, options, 0); + } + + /** + * Create a RegistryVM instance on a specified port capturing stdout and + * stderr with additional command line options. + * + * @param out the OutputStream where the normal output of the + * registry subprocess goes + * @param err the OutputStream where the error output of the + * registry subprocess goes + * @param options the command line options + * @param port the port on which Registry accepts requests + * @return a RegistryVM instance + */ + public static RegistryVM createRegistryVM(OutputStream out, OutputStream err, + String options, int port) { + return createRegistryVMWithRunner(DEFAULT_RUNNER, out, err, options, port); + } + + /** + * Create a RegistryVM instance on an ephemeral port with additional + * command line options and a specified runner. + * + * @param runner the runner class name + * @param options command line options + * @return a RegistryVM instance + */ + public static RegistryVM createRegistryVMWithRunner(String runner, String options) { + return createRegistryVMWithRunner(runner, System.out, System.err, options, 0); + } + + /** + * Create a RegistryVM instance on a specified port capturing stdout and + * stderr with additional command line options and a specified runner. + * + * @param runner the runner class name + * @param out the OutputStream where the normal output of the + * registry subprocess goes + * @param err the OutputStream where the error output of the + * registry subprocess goes + * @param options the command line options + * @param port the port on which Registry accepts requests + * @return a RegistryVM instance + */ + public static RegistryVM createRegistryVMWithRunner(String runner, OutputStream out, + OutputStream err, String options, int port) { + options += " --add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED" + + " --add-exports=java.rmi/sun.rmi.server=ALL-UNNAMED" + + " --add-exports=java.rmi/sun.rmi.transport=ALL-UNNAMED" + + " --add-exports=java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"; + RegistryVM reg = new RegistryVM(runner, out, err, options, port); + reg.setPolicyFile(TestParams.defaultRegistryPolicy); + return reg; + } + + /** + * Starts the registry in a sub-process and waits up to + * the given timeout period to confirm that it's running, + * and get the port where it's running. + * + * @throws IOException if fails to start subprocess + */ + public void start() throws IOException { + super.start(); + long startTime = System.currentTimeMillis(); + long deadline = TestLibrary.computeDeadline(startTime, (long)START_TIMEOUT); + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException ignore) { } + + String output = outputStream.ba.toString(); + port = RegistryRunner.getRegistryPort(output); + if (port != -1) { + break; + } + try { + int exit = vm.exitValue(); + TestLibrary.bomb("[RegistryVM] registry sub-process exited with status " + + exit + "."); + } catch (IllegalThreadStateException ignore) { } + + if (System.currentTimeMillis() > deadline) { + TestLibrary.bomb("Failed to start registry, giving up after " + + (System.currentTimeMillis() - startTime) + "ms.", null); + } + } + } + + /** + * Shuts down the registry. + */ + @Override + public void cleanup() { + RegistryRunner.requestExit(port); + super.destroy(); + } + + /** + * Gets the port where the registry is serving. + * + * @return the port where the registry is serving + */ + public int getPort() { + return port; + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/testlibrary/TestParams.java --- a/jdk/test/java/rmi/testlibrary/TestParams.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/testlibrary/TestParams.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +42,9 @@ /** name of default security policy for RMID */ public static final String defaultRmidPolicy; + /** name of default security policy for RegistryVM */ + public static final String defaultRegistryPolicy; + /** name of default security policy for activation groups */ public static final String defaultGroupPolicy; @@ -69,6 +72,9 @@ defaultRmidPolicy = testSrc + File.separatorChar + "rmid.security.policy"; + defaultRegistryPolicy = + testSrc + File.separatorChar + "registry.security.policy"; + defaultGroupPolicy = testSrc + File.separatorChar + "group.security.policy"; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java --- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary Test TestImpl REGISTRY RegistryRunner + * @build TestLibrary Test TestImpl RegistryVM RegistryRunner * @run main/othervm/policy=security.policy/timeout=360 DGCDeadLock */ @@ -68,21 +68,18 @@ static public void main(String[] args) { - REGISTRY testImplVM = null; + RegistryVM testImplVM = null; System.err.println("\nregression test for 4118056\n"); TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager"); try { - String options = " -Djava.security.policy=" + - TestParams.defaultPolicy + - " --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED" + + String options = " --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED" + " -Djava.rmi.dgc.leaseValue=500000" + " -Dsun.rmi.dgc.checkInterval=" + - (HOLD_TARGET_TIME - 5000) + - "" ; + (HOLD_TARGET_TIME - 5000); - testImplVM = REGISTRY.createREGISTRYWithRunner("TestImpl", options); + testImplVM = RegistryVM.createRegistryVMWithRunner("TestImpl", options); testImplVM.start(); registryPort = testImplVM.getPort(); @@ -107,7 +104,7 @@ TestLibrary.bomb("test failed in main()", e); } finally { if (testImplVM != null) { - testImplVM.shutdown(); + testImplVM.cleanup(); testImplVM = null; } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/rmi/transport/dgcDeadLock/registry.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/transport/dgcDeadLock/registry.security.policy Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,27 @@ +/* + * security policy used by the registry sub-process + */ + +grant { + // used by TestLibrary to determine extra commandline properties + permission java.io.FilePermission "..${/}..${/}test.props", "read"; + + // property specifically accessed by this test. + permission java.util.PropertyPermission "sun.rmi.transport.cleanInterval", "write"; + permission java.util.PropertyPermission "package.restrict.access.sun", "read"; + permission java.util.PropertyPermission "package.restrict.access.sun.rmi", "read"; + + // test needs to use java to exec an EchoImpl object + permission java.io.FilePermission "${java.home}${/}bin${/}java", "execute"; + + // used by TestLibrary to determine test environment + permission java.util.PropertyPermission "test.*", "read"; + permission java.util.PropertyPermission "user.dir", "read"; + permission java.util.PropertyPermission "java.home", "read"; + + permission java.util.PropertyPermission "java.security.policy", "read"; + permission java.util.PropertyPermission "java.security.manager", "read"; + + // test needs to export rmid and communicate with objects on arbitrary ports + permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; +}; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/TEST.properties --- a/jdk/test/java/time/TEST.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/TEST.properties Wed Jul 05 22:42:01 2017 +0200 @@ -1,7 +1,6 @@ # Threeten test uses TestNG TestNG.dirs = . othervm.dirs = tck/java/time/chrono test/java/time/chrono test/java/time/format -modules = jdk.localedata lib.dirs = ../../lib/testlibrary lib.build = jdk.testlibrary.RandomFactory modules = java.base/java.time:open java.base/java.time.chrono:open java.base/java.time.zone:open diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java Wed Jul 05 22:42:01 2017 +0200 @@ -880,25 +880,6 @@ } //----------------------------------------------------------------------- - @DataProvider(name="patternPrint") - Object[][] data_patternPrint() { - return new Object[][] { - {"Q", date(2012, 2, 10), "1"}, - {"QQ", date(2012, 2, 10), "01"}, - {"QQQ", date(2012, 2, 10), "Q1"}, - {"QQQQ", date(2012, 2, 10), "1st quarter"}, - {"QQQQQ", date(2012, 2, 10), "1"}, - }; - } - - @Test(dataProvider="patternPrint") - public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { - DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); - String test = f.format(temporal); - assertEquals(test, expected); - } - - //----------------------------------------------------------------------- @DataProvider(name="localePatterns") Object[][] localizedDateTimePatterns() { return new Object[][] { @@ -914,48 +895,6 @@ {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a z"}, {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a"}, {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.US, "h:mm a"}, - - // French Locale and ISO Chronology - {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y '\u00e0' HH:mm:ss zzzz"}, - {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y '\u00e0' HH:mm:ss z"}, - {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y '\u00e0' HH:mm:ss"}, - {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y HH:mm"}, - {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y"}, - {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y"}, - {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y"}, - {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y"}, - {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss zzzz"}, - {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss z"}, - {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss"}, - {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm"}, - - // Japanese Locale and JapaneseChronology - {FormatStyle.FULL, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE H\u6642mm\u5206ss\u79d2 zzzz"}, - {FormatStyle.LONG, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss z"}, - {FormatStyle.MEDIUM, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss"}, - {FormatStyle.SHORT, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d H:mm"}, - {FormatStyle.FULL, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE"}, - {FormatStyle.LONG, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"}, - {FormatStyle.MEDIUM, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"}, - {FormatStyle.SHORT, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d"}, - {null, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H\u6642mm\u5206ss\u79d2 zzzz"}, - {null, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss z"}, - {null, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss"}, - {null, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm"}, - - // Chinese Local and Chronology - {FormatStyle.FULL, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE zzzz ah:mm:ss"}, - {FormatStyle.LONG, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 z ah:mm:ss"}, - {FormatStyle.MEDIUM, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 ah:mm:ss"}, - {FormatStyle.SHORT, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d ah:mm"}, - {FormatStyle.FULL, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE"}, - {FormatStyle.LONG, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"}, - {FormatStyle.MEDIUM, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"}, - {FormatStyle.SHORT, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d"}, - {null, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "zzzz ah:mm:ss"}, - {null, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "z ah:mm:ss"}, - {null, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm:ss"}, - {null, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm"}, }; } @@ -1004,5 +943,4 @@ private static Temporal date(int y, int m, int d) { return LocalDate.of(y, m, d); } - } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilderWithLocale.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilderWithLocale.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,195 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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: + * + * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos + * + * 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 JSR-310 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. + */ + +/* + * @test + * @modules jdk.localedata + */ +package test.java.time.format; + +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.time.LocalDate; +import java.time.temporal.Temporal; + +import java.util.Locale; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatterBuilder. + */ +@Test +public class TestDateTimeFormatterBuilderWithLocale { + + private DateTimeFormatterBuilder builder; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + } + + //----------------------------------------------------------------------- + @DataProvider(name="patternPrint") + Object[][] data_patternPrint() { + return new Object[][] { + {"Q", date(2012, 2, 10), "1"}, + {"QQ", date(2012, 2, 10), "01"}, + {"QQQ", date(2012, 2, 10), "Q1"}, + {"QQQQ", date(2012, 2, 10), "1st quarter"}, + {"QQQQQ", date(2012, 2, 10), "1"}, + }; + } + + @Test(dataProvider="patternPrint") + public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { + DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); + String test = f.format(temporal); + assertEquals(test, expected); + } + + //----------------------------------------------------------------------- + @DataProvider(name="localePatterns") + Object[][] localizedDateTimePatterns() { + return new Object[][] { + // French Locale and ISO Chronology + {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y '\u00e0' HH:mm:ss zzzz"}, + {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y '\u00e0' HH:mm:ss z"}, + {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y '\u00e0' HH:mm:ss"}, + {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y HH:mm"}, + {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y"}, + {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y"}, + {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y"}, + {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y"}, + {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss zzzz"}, + {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss z"}, + {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss"}, + {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm"}, + + // Japanese Locale and JapaneseChronology + {FormatStyle.FULL, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE H\u6642mm\u5206ss\u79d2 zzzz"}, + {FormatStyle.LONG, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss z"}, + {FormatStyle.MEDIUM, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss"}, + {FormatStyle.SHORT, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d H:mm"}, + {FormatStyle.FULL, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE"}, + {FormatStyle.LONG, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"}, + {FormatStyle.MEDIUM, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"}, + {FormatStyle.SHORT, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d"}, + {null, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H\u6642mm\u5206ss\u79d2 zzzz"}, + {null, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss z"}, + {null, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss"}, + {null, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm"}, + + // Chinese Local and Chronology + {FormatStyle.FULL, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE zzzz ah:mm:ss"}, + {FormatStyle.LONG, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 z ah:mm:ss"}, + {FormatStyle.MEDIUM, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 ah:mm:ss"}, + {FormatStyle.SHORT, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d ah:mm"}, + {FormatStyle.FULL, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE"}, + {FormatStyle.LONG, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"}, + {FormatStyle.MEDIUM, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"}, + {FormatStyle.SHORT, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d"}, + {null, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "zzzz ah:mm:ss"}, + {null, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "z ah:mm:ss"}, + {null, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm:ss"}, + {null, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm"}, + }; + } + + @Test(dataProvider="localePatterns") + public void test_getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle, + Chronology chrono, Locale locale, String expected) { + String actual = DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale); + assertEquals(actual, expected, "Pattern " + convertNonAscii(actual)); + } + + /** + * Returns a string that includes non-ascii characters after expanding + * the non-ascii characters to their Java language \\uxxxx form. + * @param input an input string + * @return the encoded string. + */ + private String convertNonAscii(String input) { + StringBuilder sb = new StringBuilder(input.length() * 6); + for (int i = 0; i < input.length(); i++) { + char ch = input.charAt(i); + if (ch < 255) { + sb.append(ch); + } else { + sb.append("\\u"); + sb.append(Integer.toHexString(ch)); + } + } + return sb.toString(); + } + + private static Temporal date(int y, int m, int d) { + return LocalDate.of(y, m, d); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java --- a/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 @@ -80,7 +80,6 @@ public class TestDateTimeTextProvider extends AbstractTestPrinterParser { Locale enUS = new Locale("en", "US"); - Locale ptBR = new Locale("pt", "BR"); //----------------------------------------------------------------------- @DataProvider(name = "Text") @@ -94,14 +93,6 @@ {DAY_OF_WEEK, 6, TextStyle.SHORT, enUS, "Sat"}, {DAY_OF_WEEK, 7, TextStyle.SHORT, enUS, "Sun"}, - {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "seg"}, - {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "ter"}, - {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "qua"}, - {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "qui"}, - {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "sex"}, - {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "s\u00E1b"}, - {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "dom"}, - {DAY_OF_WEEK, 1, TextStyle.FULL, enUS, "Monday"}, {DAY_OF_WEEK, 2, TextStyle.FULL, enUS, "Tuesday"}, {DAY_OF_WEEK, 3, TextStyle.FULL, enUS, "Wednesday"}, @@ -110,14 +101,6 @@ {DAY_OF_WEEK, 6, TextStyle.FULL, enUS, "Saturday"}, {DAY_OF_WEEK, 7, TextStyle.FULL, enUS, "Sunday"}, - {DAY_OF_WEEK, 1, TextStyle.FULL, ptBR, "segunda-feira"}, - {DAY_OF_WEEK, 2, TextStyle.FULL, ptBR, "ter\u00E7a-feira"}, - {DAY_OF_WEEK, 3, TextStyle.FULL, ptBR, "quarta-feira"}, - {DAY_OF_WEEK, 4, TextStyle.FULL, ptBR, "quinta-feira"}, - {DAY_OF_WEEK, 5, TextStyle.FULL, ptBR, "sexta-feira"}, - {DAY_OF_WEEK, 6, TextStyle.FULL, ptBR, "s\u00E1bado"}, - {DAY_OF_WEEK, 7, TextStyle.FULL, ptBR, "domingo"}, - {MONTH_OF_YEAR, 1, TextStyle.SHORT, enUS, "Jan"}, {MONTH_OF_YEAR, 2, TextStyle.SHORT, enUS, "Feb"}, {MONTH_OF_YEAR, 3, TextStyle.SHORT, enUS, "Mar"}, @@ -131,19 +114,6 @@ {MONTH_OF_YEAR, 11, TextStyle.SHORT, enUS, "Nov"}, {MONTH_OF_YEAR, 12, TextStyle.SHORT, enUS, "Dec"}, - {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "jan"}, - {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "fev"}, - {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "mar"}, - {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "abr"}, - {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "mai"}, - {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "jun"}, - {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "jul"}, - {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "ago"}, - {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "set"}, - {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "out"}, - {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "nov"}, - {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "dez"}, - {MONTH_OF_YEAR, 1, TextStyle.FULL, enUS, "January"}, {MONTH_OF_YEAR, 2, TextStyle.FULL, enUS, "February"}, {MONTH_OF_YEAR, 3, TextStyle.FULL, enUS, "March"}, @@ -157,19 +127,6 @@ {MONTH_OF_YEAR, 11, TextStyle.FULL, enUS, "November"}, {MONTH_OF_YEAR, 12, TextStyle.FULL, enUS, "December"}, - {MONTH_OF_YEAR, 1, TextStyle.FULL, ptBR, "janeiro"}, - {MONTH_OF_YEAR, 2, TextStyle.FULL, ptBR, "fevereiro"}, - {MONTH_OF_YEAR, 3, TextStyle.FULL, ptBR, "mar\u00E7o"}, - {MONTH_OF_YEAR, 4, TextStyle.FULL, ptBR, "abril"}, - {MONTH_OF_YEAR, 5, TextStyle.FULL, ptBR, "maio"}, - {MONTH_OF_YEAR, 6, TextStyle.FULL, ptBR, "junho"}, - {MONTH_OF_YEAR, 7, TextStyle.FULL, ptBR, "julho"}, - {MONTH_OF_YEAR, 8, TextStyle.FULL, ptBR, "agosto"}, - {MONTH_OF_YEAR, 9, TextStyle.FULL, ptBR, "setembro"}, - {MONTH_OF_YEAR, 10, TextStyle.FULL, ptBR, "outubro"}, - {MONTH_OF_YEAR, 11, TextStyle.FULL, ptBR, "novembro"}, - {MONTH_OF_YEAR, 12, TextStyle.FULL, ptBR, "dezembro"}, - {AMPM_OF_DAY, 0, TextStyle.SHORT, enUS, "AM"}, {AMPM_OF_DAY, 1, TextStyle.SHORT, enUS, "PM"}, diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestDateTimeTextProviderWithLocale.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProviderWithLocale.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,146 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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: + * + * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos + * + * 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 JSR-310 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. + */ + +/* + * @test + * @modules jdk.localedata + */ + +package test.java.time.format; + +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static org.testng.Assert.assertEquals; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.time.temporal.TemporalField; +import java.util.Locale; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test SimpleDateTimeTextProviderWithLocale. + */ +@Test +public class TestDateTimeTextProviderWithLocale extends AbstractTestPrinterParser { + + Locale enUS = new Locale("en", "US"); + Locale ptBR = new Locale("pt", "BR"); + + //----------------------------------------------------------------------- + @DataProvider(name = "Text") + Object[][] data_text() { + return new Object[][] { + {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "seg"}, + {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "ter"}, + {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "qua"}, + {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "qui"}, + {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "sex"}, + {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "s\u00E1b"}, + {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "dom"}, + + {DAY_OF_WEEK, 1, TextStyle.FULL, ptBR, "segunda-feira"}, + {DAY_OF_WEEK, 2, TextStyle.FULL, ptBR, "ter\u00E7a-feira"}, + {DAY_OF_WEEK, 3, TextStyle.FULL, ptBR, "quarta-feira"}, + {DAY_OF_WEEK, 4, TextStyle.FULL, ptBR, "quinta-feira"}, + {DAY_OF_WEEK, 5, TextStyle.FULL, ptBR, "sexta-feira"}, + {DAY_OF_WEEK, 6, TextStyle.FULL, ptBR, "s\u00E1bado"}, + {DAY_OF_WEEK, 7, TextStyle.FULL, ptBR, "domingo"}, + + {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "jan"}, + {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "fev"}, + {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "mar"}, + {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "abr"}, + {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "mai"}, + {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "jun"}, + {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "jul"}, + {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "ago"}, + {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "set"}, + {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "out"}, + {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "nov"}, + {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "dez"}, + + {MONTH_OF_YEAR, 1, TextStyle.FULL, ptBR, "janeiro"}, + {MONTH_OF_YEAR, 2, TextStyle.FULL, ptBR, "fevereiro"}, + {MONTH_OF_YEAR, 3, TextStyle.FULL, ptBR, "mar\u00E7o"}, + {MONTH_OF_YEAR, 4, TextStyle.FULL, ptBR, "abril"}, + {MONTH_OF_YEAR, 5, TextStyle.FULL, ptBR, "maio"}, + {MONTH_OF_YEAR, 6, TextStyle.FULL, ptBR, "junho"}, + {MONTH_OF_YEAR, 7, TextStyle.FULL, ptBR, "julho"}, + {MONTH_OF_YEAR, 8, TextStyle.FULL, ptBR, "agosto"}, + {MONTH_OF_YEAR, 9, TextStyle.FULL, ptBR, "setembro"}, + {MONTH_OF_YEAR, 10, TextStyle.FULL, ptBR, "outubro"}, + {MONTH_OF_YEAR, 11, TextStyle.FULL, ptBR, "novembro"}, + {MONTH_OF_YEAR, 12, TextStyle.FULL, ptBR, "dezembro"}, + + }; + } + + @Test(dataProvider = "Text") + public void test_getText(TemporalField field, Number value, TextStyle style, Locale locale, String expected) { + DateTimeFormatter fmt = getFormatter(field, style).withLocale(locale); + assertEquals(fmt.format(ZonedDateTime.now().with(field, value.longValue())), expected); + } + +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestNarrowMonthNamesAndDayNames.java --- a/jdk/test/java/time/test/java/time/format/TestNarrowMonthNamesAndDayNames.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/test/java/time/format/TestNarrowMonthNamesAndDayNames.java Wed Jul 05 22:42:01 2017 +0200 @@ -20,13 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package test.java.time.format; - /* * @test + * @modules jdk.localedata * @bug 8146750 * @summary Test Narrow and NarrowStandalone month names are retrieved correctly. */ +package test.java.time.format; + import static org.testng.Assert.assertEquals; import java.time.DayOfWeek; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java --- a/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java Wed Jul 05 22:42:01 2017 +0200 @@ -20,6 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* + * + * @test + * @modules jdk.localedata + */ + package test.java.time.format; import static org.testng.Assert.assertEquals; diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestTextParser.java --- a/jdk/test/java/time/test/java/time/format/TestTextParser.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/test/java/time/format/TestTextParser.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 @@ -68,16 +68,9 @@ import java.text.ParsePosition; import java.time.DayOfWeek; -import java.time.chrono.ChronoLocalDate; -import java.time.chrono.JapaneseChronology; -import java.time.chrono.HijrahDate; -import java.time.chrono.JapaneseDate; -import java.time.chrono.MinguoDate; -import java.time.chrono.ThaiBuddhistDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.TextStyle; -import java.time.format.SignStyle; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQueries; @@ -92,8 +85,6 @@ */ @Test public class TestTextParser extends AbstractTestPrinterParser { - static final Locale RUSSIAN = new Locale("ru"); - static final Locale FINNISH = new Locale("fi"); //----------------------------------------------------------------------- @DataProvider(name="error") @@ -213,20 +204,6 @@ }; } - // Test data is dependent on localized resources. - @DataProvider(name="parseStandaloneText") - Object[][] providerStandaloneText() { - // Locale, TemporalField, TextStyle, expected value, input text - return new Object[][] { - {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE, 1, "\u044f\u043d\u0432\u0430\u0440\u044c"}, - {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE, 12, "\u0434\u0435\u043a\u0430\u0431\u0440\u044c"}, - {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, 1, "\u044f\u043d\u0432."}, - {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, 12, "\u0434\u0435\u043a."}, - {FINNISH, DAY_OF_WEEK, TextStyle.FULL_STANDALONE, 2, "tiistai"}, - {FINNISH, DAY_OF_WEEK, TextStyle.SHORT_STANDALONE, 2, "ti"}, - }; - } - @DataProvider(name="parseDayOfWeekText") Object[][] providerDayOfWeekData() { return new Object[][] { @@ -234,26 +211,9 @@ {Locale.US, "e", "1", DayOfWeek.SUNDAY}, {Locale.US, "ee", "01", DayOfWeek.SUNDAY}, {Locale.US, "c", "1", DayOfWeek.SUNDAY}, - - {Locale.UK, "e", "1", DayOfWeek.MONDAY}, - {Locale.UK, "ee", "01", DayOfWeek.MONDAY}, - {Locale.UK, "c", "1", DayOfWeek.MONDAY}, }; } - // Test data is dependent on localized resources. - @DataProvider(name="parseLenientText") - Object[][] providerLenientText() { - // Locale, TemporalField, expected value, input text - return new Object[][] { - {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044f"}, // full format - {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044c"}, // full standalone - {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432."}, // short format - {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432."}, // short standalone - }; - } - - @Test(dataProvider="parseText") public void test_parseText(TemporalField field, TextStyle style, int value, String input) throws Exception { @@ -269,14 +229,6 @@ assertEquals(pos.getIndex(), input.length()); } - @Test(dataProvider="parseStandaloneText") - public void test_parseStandaloneText(Locale locale, TemporalField field, TextStyle style, int expectedValue, String input) { - DateTimeFormatter formatter = getFormatter(field, style).withLocale(locale); - ParsePosition pos = new ParsePosition(0); - assertEquals(formatter.parseUnresolved(input, pos).getLong(field), (long) expectedValue); - assertEquals(pos.getIndex(), input.length()); - } - @Test(dataProvider="parseDayOfWeekText") public void test_parseDayOfWeekText(Locale locale, String pattern, String input, DayOfWeek expected) { DateTimeFormatter formatter = getPatternFormatter(pattern).withLocale(locale); @@ -374,25 +326,6 @@ } //----------------------------------------------------------------------- - public void test_parse_french_short_strict_full_noMatch() throws Exception { - setStrict(true); - ParsePosition pos = new ParsePosition(0); - getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) - .parseUnresolved("janvier", pos); - assertEquals(pos.getErrorIndex(), 0); - } - - public void test_parse_french_short_strict_short_match() throws Exception { - setStrict(true); - ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) - .parseUnresolved("janv.", pos) - .getLong(MONTH_OF_YEAR), - 1L); - assertEquals(pos.getIndex(), 5); - } - - //----------------------------------------------------------------------- public void test_parse_full_lenient_full_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); @@ -436,51 +369,4 @@ assertEquals(pos.getIndex(), 1); } - @Test(dataProvider="parseLenientText") - public void test_parseLenientText(Locale locale, TemporalField field, int expectedValue, String input) { - setStrict(false); - ParsePosition pos = new ParsePosition(0); - DateTimeFormatter formatter = getFormatter(field).withLocale(locale); - assertEquals(formatter.parseUnresolved(input, pos).getLong(field), (long) expectedValue); - assertEquals(pos.getIndex(), input.length()); - } - - //----------------------------------------------------------------------- - @DataProvider(name="parseChronoLocalDate") - Object[][] provider_chronoLocalDate() { - return new Object[][] { - { HijrahDate.now() }, - { JapaneseDate.now() }, - { MinguoDate.now() }, - { ThaiBuddhistDate.now() }}; - } - - private static final DateTimeFormatter fmt_chrono = - new DateTimeFormatterBuilder() - .optionalStart() - .appendChronologyId() - .appendLiteral(' ') - .optionalEnd() - .optionalStart() - .appendText(ChronoField.ERA, TextStyle.SHORT) - .appendLiteral(' ') - .optionalEnd() - .appendValue(ChronoField.YEAR_OF_ERA, 1, 9, SignStyle.NORMAL) - .appendLiteral('-') - .appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NEVER) - .appendLiteral('-') - .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) - .toFormatter(); - - @Test(dataProvider="parseChronoLocalDate") - public void test_chronoLocalDate(ChronoLocalDate date) throws Exception { - System.out.printf(" %s, [fmt=%s]%n", date, fmt_chrono.format(date)); - assertEquals(date, fmt_chrono.parse(fmt_chrono.format(date), ChronoLocalDate::from)); - - DateTimeFormatter fmt = DateTimeFormatter.ofPattern("[GGG ]yyy-MM-dd") - .withChronology(date.getChronology()); - System.out.printf(" %s, [fmt=%s]%n", date.toString(), fmt.format(date)); - assertEquals(date, fmt.parse(fmt.format(date), ChronoLocalDate::from)); - } - } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestTextParserWithLocale.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestTextParserWithLocale.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,226 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * 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 JSR-310 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. + */ + +/* + * @test + * @modules jdk.localedata + */ + +package test.java.time.format; + +import java.text.ParsePosition; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.HijrahDate; +import java.time.chrono.JapaneseDate; +import java.time.chrono.MinguoDate; +import java.time.chrono.ThaiBuddhistDate; +import java.time.DayOfWeek; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.time.format.SignStyle; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalField; +import java.util.Locale; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static org.testng.Assert.assertEquals; + +/** + * Test TextPrinterParser. + */ +@Test +public class TestTextParserWithLocale extends AbstractTestPrinterParser { + static final Locale RUSSIAN = new Locale("ru"); + static final Locale FINNISH = new Locale("fi"); + + @DataProvider(name="parseDayOfWeekText") + Object[][] providerDayOfWeekData() { + return new Object[][] { + // Locale, pattern, input text, expected DayOfWeek + {Locale.US, "e", "1", DayOfWeek.SUNDAY}, + {Locale.US, "ee", "01", DayOfWeek.SUNDAY}, + {Locale.US, "c", "1", DayOfWeek.SUNDAY}, + + {Locale.UK, "e", "1", DayOfWeek.MONDAY}, + {Locale.UK, "ee", "01", DayOfWeek.MONDAY}, + {Locale.UK, "c", "1", DayOfWeek.MONDAY}, + }; + } + + @Test(dataProvider="parseDayOfWeekText") + public void test_parseDayOfWeekText(Locale locale, String pattern, String input, DayOfWeek expected) { + DateTimeFormatter formatter = getPatternFormatter(pattern).withLocale(locale); + ParsePosition pos = new ParsePosition(0); + assertEquals(DayOfWeek.from(formatter.parse(input, pos)), expected); + assertEquals(pos.getIndex(), input.length()); + } + + //-------------------------------------------------------------------- + // Test data is dependent on localized resources. + @DataProvider(name="parseStandaloneText") + Object[][] providerStandaloneText() { + // Locale, TemporalField, TextStyle, expected value, input text + return new Object[][] { + {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE, 1, "\u044f\u043d\u0432\u0430\u0440\u044c"}, + {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE, 12, "\u0434\u0435\u043a\u0430\u0431\u0440\u044c"}, + {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, 1, "\u044f\u043d\u0432."}, + {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, 12, "\u0434\u0435\u043a."}, + {FINNISH, DAY_OF_WEEK, TextStyle.FULL_STANDALONE, 2, "tiistai"}, + {FINNISH, DAY_OF_WEEK, TextStyle.SHORT_STANDALONE, 2, "ti"}, + }; + } + + // Test data is dependent on localized resources. + @DataProvider(name="parseLenientText") + Object[][] providerLenientText() { + // Locale, TemporalField, expected value, input text + return new Object[][] { + {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044f"}, // full format + {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432\u0430\u0440\u044c"}, // full standalone + {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432."}, // short format + {RUSSIAN, MONTH_OF_YEAR, 1, "\u044f\u043d\u0432."}, // short standalone + }; + } + + @Test(dataProvider="parseStandaloneText") + public void test_parseStandaloneText(Locale locale, TemporalField field, TextStyle style, int expectedValue, String input) { + DateTimeFormatter formatter = getFormatter(field, style).withLocale(locale); + ParsePosition pos = new ParsePosition(0); + assertEquals(formatter.parseUnresolved(input, pos).getLong(field), (long) expectedValue); + assertEquals(pos.getIndex(), input.length()); + } + + //----------------------------------------------------------------------- + public void test_parse_french_short_strict_full_noMatch() throws Exception { + setStrict(true); + ParsePosition pos = new ParsePosition(0); + getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) + .parseUnresolved("janvier", pos); + assertEquals(pos.getErrorIndex(), 0); + } + + public void test_parse_french_short_strict_short_match() throws Exception { + setStrict(true); + ParsePosition pos = new ParsePosition(0); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) + .parseUnresolved("janv.", pos) + .getLong(MONTH_OF_YEAR), + 1L); + assertEquals(pos.getIndex(), 5); + } + + //----------------------------------------------------------------------- + + @Test(dataProvider="parseLenientText") + public void test_parseLenientText(Locale locale, TemporalField field, int expectedValue, String input) { + setStrict(false); + ParsePosition pos = new ParsePosition(0); + DateTimeFormatter formatter = getFormatter(field).withLocale(locale); + assertEquals(formatter.parseUnresolved(input, pos).getLong(field), (long) expectedValue); + assertEquals(pos.getIndex(), input.length()); + } + + + //----------------------------------------------------------------------- + @DataProvider(name="parseChronoLocalDate") + Object[][] provider_chronoLocalDate() { + return new Object[][] { + { HijrahDate.now() }, + { JapaneseDate.now() }, + { MinguoDate.now() }, + { ThaiBuddhistDate.now() }}; + } + + private static final DateTimeFormatter fmt_chrono = + new DateTimeFormatterBuilder() + .optionalStart() + .appendChronologyId() + .appendLiteral(' ') + .optionalEnd() + .optionalStart() + .appendText(ChronoField.ERA, TextStyle.SHORT) + .appendLiteral(' ') + .optionalEnd() + .appendValue(ChronoField.YEAR_OF_ERA, 1, 9, SignStyle.NORMAL) + .appendLiteral('-') + .appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NEVER) + .appendLiteral('-') + .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) + .toFormatter(); + + @Test(dataProvider="parseChronoLocalDate") + public void test_chronoLocalDate(ChronoLocalDate date) throws Exception { + System.out.printf(" %s, [fmt=%s]%n", date, fmt_chrono.format(date)); + assertEquals(date, fmt_chrono.parse(fmt_chrono.format(date), ChronoLocalDate::from)); + + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("[GGG ]yyy-MM-dd") + .withChronology(date.getChronology()); + System.out.printf(" %s, [fmt=%s]%n", date.toString(), fmt.format(date)); + assertEquals(date, fmt.parse(fmt.format(date), ChronoLocalDate::from)); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestTextPrinter.java --- a/jdk/test/java/time/test/java/time/format/TestTextPrinter.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/time/test/java/time/format/TestTextPrinter.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 @@ -84,8 +84,6 @@ */ @Test public class TestTextPrinter extends AbstractTestPrinterParser { - static final Locale RUSSIAN = new Locale("ru"); - static final Locale FINNISH = new Locale("fi"); //----------------------------------------------------------------------- @Test(expectedExceptions=DateTimeException.class) @@ -213,32 +211,6 @@ {Locale.US, "e", "1", DayOfWeek.SUNDAY}, {Locale.US, "ee", "01", DayOfWeek.SUNDAY}, {Locale.US, "c", "1", DayOfWeek.SUNDAY}, - - {Locale.UK, "e", "1", DayOfWeek.MONDAY}, - {Locale.UK, "ee", "01", DayOfWeek.MONDAY}, - {Locale.UK, "c", "1", DayOfWeek.MONDAY}, - }; - } - - @DataProvider(name="print_JapaneseChronology") - Object[][] provider_japaneseEra() { - return new Object[][] { - {ERA, TextStyle.FULL, 2, "Heisei"}, // Note: CLDR doesn't define "wide" Japanese era names. - {ERA, TextStyle.SHORT, 2, "Heisei"}, - {ERA, TextStyle.NARROW, 2, "H"}, - }; - }; - - // Test data is dependent on localized resources. - @DataProvider(name="print_standalone") - Object[][] provider_StandaloneNames() { - return new Object[][] { - // standalone names for 2013-01-01 (Tue) - // Locale, TemporalField, TextStyle, expected text - {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE, "\u044f\u043d\u0432\u0430\u0440\u044c"}, - {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, "\u044f\u043d\u0432."}, - {FINNISH, DAY_OF_WEEK, TextStyle.FULL_STANDALONE, "tiistai"}, - {FINNISH, DAY_OF_WEEK, TextStyle.SHORT_STANDALONE, "ti"}, }; } @@ -255,30 +227,6 @@ assertEquals(text, expected); } - @Test(dataProvider="print_JapaneseChronology") - public void test_formatJapaneseEra(TemporalField field, TextStyle style, int value, String expected) throws Exception { - LocalDate ld = LocalDate.of(2013, 1, 31); - getFormatter(field, style).withChronology(JapaneseChronology.INSTANCE).formatTo(ld, buf); - assertEquals(buf.toString(), expected); - } - - @Test(dataProvider="print_standalone") - public void test_standaloneNames(Locale locale, TemporalField field, TextStyle style, String expected) { - getFormatter(field, style).withLocale(locale).formatTo(LocalDate.of(2013, 1, 1), buf); - assertEquals(buf.toString(), expected); - } - - //----------------------------------------------------------------------- - public void test_print_french_long() throws Exception { - getFormatter(MONTH_OF_YEAR, TextStyle.FULL).withLocale(Locale.FRENCH).formatTo(LocalDate.of(2012, 1, 1), buf); - assertEquals(buf.toString(), "janvier"); - } - - public void test_print_french_short() throws Exception { - getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH).formatTo(LocalDate.of(2012, 1, 1), buf); - assertEquals(buf.toString(), "janv."); - } - //----------------------------------------------------------------------- public void test_toString1() throws Exception { assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).toString(), "Text(MonthOfYear)"); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/time/test/java/time/format/TestTextPrinterWithLocale.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestTextPrinterWithLocale.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,163 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * 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 JSR-310 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. + */ + +/* + * @test + * @modules jdk.localedata + */ + +package test.java.time.format; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.IsoFields.QUARTER_OF_YEAR; +import static org.testng.Assert.assertEquals; + +import java.time.DateTimeException; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.chrono.JapaneseChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.time.temporal.TemporalField; +import java.util.Locale; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import test.java.time.temporal.MockFieldValue; + +/** + * Test TextPrinterParserWithLocale. + */ +@Test +public class TestTextPrinterWithLocale extends AbstractTestPrinterParser { + static final Locale RUSSIAN = new Locale("ru"); + static final Locale FINNISH = new Locale("fi"); + + //----------------------------------------------------------------------- + @DataProvider(name="print_DayOfWeekData") + Object[][] providerDayOfWeekData() { + return new Object[][] { + // Locale, pattern, expected text, input DayOfWeek + {Locale.US, "e", "1", DayOfWeek.SUNDAY}, + {Locale.US, "ee", "01", DayOfWeek.SUNDAY}, + {Locale.US, "c", "1", DayOfWeek.SUNDAY}, + + {Locale.UK, "e", "1", DayOfWeek.MONDAY}, + {Locale.UK, "ee", "01", DayOfWeek.MONDAY}, + {Locale.UK, "c", "1", DayOfWeek.MONDAY}, + }; + } + + // Test data is dependent on localized resources. + @DataProvider(name="print_standalone") + Object[][] provider_StandaloneNames() { + return new Object[][] { + // standalone names for 2013-01-01 (Tue) + // Locale, TemporalField, TextStyle, expected text + {RUSSIAN, MONTH_OF_YEAR, TextStyle.FULL_STANDALONE, "\u044f\u043d\u0432\u0430\u0440\u044c"}, + {RUSSIAN, MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE, "\u044f\u043d\u0432."}, + {FINNISH, DAY_OF_WEEK, TextStyle.FULL_STANDALONE, "tiistai"}, + {FINNISH, DAY_OF_WEEK, TextStyle.SHORT_STANDALONE, "ti"}, + }; + } + + @Test(dataProvider="print_DayOfWeekData") + public void test_formatDayOfWeek(Locale locale, String pattern, String expected, DayOfWeek dayOfWeek) { + DateTimeFormatter formatter = getPatternFormatter(pattern).withLocale(locale); + String text = formatter.format(dayOfWeek); + assertEquals(text, expected); + } + + @Test(dataProvider="print_standalone") + public void test_standaloneNames(Locale locale, TemporalField field, TextStyle style, String expected) { + getFormatter(field, style).withLocale(locale).formatTo(LocalDate.of(2013, 1, 1), buf); + assertEquals(buf.toString(), expected); + } + + //----------------------------------------------------------------------- + public void test_print_french_long() throws Exception { + getFormatter(MONTH_OF_YEAR, TextStyle.FULL).withLocale(Locale.FRENCH).formatTo(LocalDate.of(2012, 1, 1), buf); + assertEquals(buf.toString(), "janvier"); + } + + public void test_print_french_short() throws Exception { + getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH).formatTo(LocalDate.of(2012, 1, 1), buf); + assertEquals(buf.toString(), "janv."); + } + + @DataProvider(name="print_JapaneseChronology") + Object[][] provider_japaneseEra() { + return new Object[][] { + {ERA, TextStyle.FULL, 2, "Heisei"}, // Note: CLDR doesn't define "wide" Japanese era names. + {ERA, TextStyle.SHORT, 2, "Heisei"}, + {ERA, TextStyle.NARROW, 2, "H"}, + }; + }; + + @Test(dataProvider="print_JapaneseChronology") + public void test_formatJapaneseEra(TemporalField field, TextStyle style, int value, String expected) throws Exception { + LocalDate ld = LocalDate.of(2013, 1, 31); + getFormatter(field, style).withChronology(JapaneseChronology.INSTANCE).formatTo(ld, buf); + assertEquals(buf.toString(), expected); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/util/Collection/SetFactories.java --- a/jdk/test/java/util/Collection/SetFactories.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/util/Collection/SetFactories.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +103,8 @@ hashSetOf("a", "b", "c", "d", "e", "f", "g", "h", "i")), a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), hashSetOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")), + a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), + Set.of("j", "i", "h", "g", "f", "e", "d", "c", "b", "a")), a( Set.of(stringArray), hashSetOf(stringArray)) ).iterator(); @@ -183,6 +185,17 @@ Set set = Set.of(array); } + @Test(dataProvider="all") + public void hashCodeEqual(Set act, Set exp) { + assertEquals(act.hashCode(), exp.hashCode()); + } + + @Test(dataProvider="all") + public void containsAll(Set act, Set exp) { + assertTrue(act.containsAll(exp)); + assertTrue(exp.containsAll(act)); + } + @Test(expectedExceptions=NullPointerException.class) public void nullDisallowed1() { Set.of((String)null); // force one-arg overload diff -r 047a57b0839a -r 1c9922f121ff jdk/test/java/util/Map/MapFactories.java --- a/jdk/test/java/util/Map/MapFactories.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/java/util/Map/MapFactories.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +103,8 @@ a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h"), genMap(8)), a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i"), genMap(9)), a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"), genMap(10)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"), + Map.of(4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j", 0, "a", 1, "b", 2, "c", 3, "d")), a(Map.ofEntries(genEntries(MAX_ENTRIES)), genMap(MAX_ENTRIES)) ).iterator(); } @@ -135,6 +137,18 @@ assertEquals(act, exp); } + @Test(dataProvider="all") + public void containsAllKeys(Map act, Map exp) { + assertTrue(act.keySet().containsAll(exp.keySet())); + assertTrue(exp.keySet().containsAll(act.keySet())); + } + + @Test(dataProvider="all") + public void containsAllValues(Map act, Map exp) { + assertTrue(act.values().containsAll(exp.values())); + assertTrue(exp.values().containsAll(act.values())); + } + @Test(expectedExceptions=IllegalArgumentException.class) public void dupKeysDisallowed2() { Map map = Map.of(0, "a", 0, "b"); @@ -192,6 +206,11 @@ Map map = Map.ofEntries(entries); } + @Test(dataProvider="all") + public void hashCodeEquals(Map act, Map exp) { + assertEquals(act.hashCode(), exp.hashCode()); + } + @Test(expectedExceptions=NullPointerException.class) public void nullKeyDisallowed1() { Map map = Map.of(null, "a"); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/javax/swing/JTable/8133919/DrawGridLinesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JTable/8133919/DrawGridLinesTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,103 @@ +/* + * 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.Graphics2D; +import java.awt.image.BufferedImage; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 8133919 + * @summary [macosx] JTable grid lines are incorrectly positioned on HiDPI display + * @run main DrawGridLinesTest + */ +public class DrawGridLinesTest { + + private static final int WIDTH = 300; + private static final int HEIGHT = 150; + private static final Color GRID_COLOR = Color.BLACK; + private static final Color TABLE_BACKGROUND_COLOR = Color.BLUE; + private static final Color CELL_RENDERER_BACKGROUND_COLOR = Color.YELLOW; + private static final int SCALE = 2; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(DrawGridLinesTest::checkTableGridLines); + } + + private static void checkTableGridLines() { + + TableModel dataModel = new AbstractTableModel() { + public int getColumnCount() { + return 10; + } + + public int getRowCount() { + return 10; + } + + public Object getValueAt(int row, int col) { + return " "; + } + }; + + DefaultTableCellRenderer r = new DefaultTableCellRenderer(); + r.setOpaque(true); + r.setBackground(CELL_RENDERER_BACKGROUND_COLOR); + + JTable table = new JTable(dataModel); + table.setSize(WIDTH, HEIGHT); + table.setDefaultRenderer(Object.class, r); + table.setGridColor(GRID_COLOR); + table.setShowGrid(true); + table.setShowHorizontalLines(true); + table.setShowVerticalLines(true); + table.setBackground(TABLE_BACKGROUND_COLOR); + + checkTableGridLines(table); + } + + private static void checkTableGridLines(JTable table) { + + int w = SCALE * WIDTH; + int h = SCALE * HEIGHT; + + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Graphics2D g = img.createGraphics(); + g.scale(SCALE, SCALE); + table.paint(g); + g.dispose(); + + int size = Math.min(w, h); + int rgb = TABLE_BACKGROUND_COLOR.getRGB(); + + for (int i = 0; i < size; i++) { + if (img.getRGB(i, i) == rgb || img.getRGB(i, size - i - 1) == rgb) { + throw new RuntimeException("Artifacts in the table background color!"); + } + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/javax/swing/JTable/PrintManualTest_FitWidthMultiple.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JTable/PrintManualTest_FitWidthMultiple.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,218 @@ +/* + * 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 8170349 + * @summary Verify if printed content is within border and all columns are + * printed for PrintMode.FIT_WIDTH + * @run main/manual PrintManualTest_FitWidthMultiple + */ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.text.MessageFormat; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +public class PrintManualTest_FitWidthMultiple extends JTable implements Runnable { + + static boolean testPassed; + static JFrame fr = null; + static JFrame instructFrame = null; + private final CountDownLatch latch; + + public PrintManualTest_FitWidthMultiple(CountDownLatch latch){ + this.latch = latch; + } + + @Override + public void run() { + try { + createUIandTest(); + } catch (Exception ex) { + dispose(); + latch.countDown(); + throw new RuntimeException(ex.getMessage()); + } + } + + private void createUIandTest() throws Exception { + /*Message Format Header and Footer */ + final MessageFormat header=new MessageFormat("JTable Printing Header {0}"); + final MessageFormat footer = new MessageFormat("JTable Printing Footer {0}"); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + /* Instructions Section */ + String info = + " \nThis test case brings up JTable with more Columns and Rows \n"+ + "Press the Print Button. It Prints in PRINT_MODE_FIT_WIDTH \n" + + "It Pops up the Print Dialog. Check if Job/Print Attributes in the\n" + + "Print Dialog are configurable. Default Print out will be in Landscape \n"+ + "The Print out should have JTable Centered on the Print out with thin borders \n"+ + "Prints out with Header and Footer. \n"+ + "The JTable should have all columns printed within border"; + + instructFrame=new JFrame("PrintManualTest_NormalSingle"); + JPanel panel=new JPanel(new BorderLayout()); + JButton button1 = new JButton("Pass"); + JButton button2 = new JButton("Fail"); + button1.addActionListener((e) -> { + testPassed = true; + dispose(); + latch.countDown(); + }); + button2.addActionListener((e) -> { + testPassed = false; + dispose(); + latch.countDown(); + }); + JPanel btnpanel1 = new JPanel(); + btnpanel1.add(button1); + btnpanel1.add(button2); + panel.add(addInfo(info),BorderLayout.CENTER); + panel.add(btnpanel1, BorderLayout.SOUTH); + instructFrame.getContentPane().add(panel); + instructFrame.setBounds(600,100,350,350); + + /* Print Button */ + final JButton printButton=new JButton("Print"); + + /* Table Model */ + final TableModel datamodel=new AbstractTableModel(){ + @Override + public int getColumnCount() { return 50;} + @Override + public int getRowCount() { return 50; } + @Override + public Object getValueAt(int row, int column){ return new Integer(row*column);} + }; + + /* Constructing the JTable */ + final JTable table=new JTable(datamodel); + + /* Putting the JTable in ScrollPane and Frame Container */ + JScrollPane scrollpane=new JScrollPane(table); + fr = new JFrame("PrintManualTest_FitWidthMultiple"); + fr.getContentPane().add(scrollpane); + + /* Light Weight Panel for holding Print and other buttons */ + JPanel btnpanel=new JPanel(); + btnpanel.add(printButton); + fr.getContentPane().add(btnpanel,BorderLayout.SOUTH); + fr.setBounds(0,0,400,400); + fr.setSize(500,500); + + /* Binding the KeyStroke to Print Button Action */ + fr.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ctrl P"), "printButton"); + fr.getRootPane().getActionMap().put("printButton", new AbstractAction(){ + @Override + public void actionPerformed(ActionEvent e){ + printButton.doClick(); + } + }); + + /* Container and Component Listeners */ + fr.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + dispose(); + if (testPassed == false) { + throw new RuntimeException(" User has not executed the test"); + } + } + }); + + final PrintRequestAttributeSet prattr=new HashPrintRequestAttributeSet(); + prattr.add(javax.print.attribute.standard.OrientationRequested.LANDSCAPE); + + printButton.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent ae){ + try{ + table.print(JTable.PrintMode.FIT_WIDTH, header,footer,true,prattr,true); + } catch(Exception e){} + } + }); + instructFrame.setVisible(true); + fr.setVisible(true); + } + }); + } + + public void dispose() { + instructFrame.dispose(); + fr.dispose(); + } + + public JScrollPane addInfo(String info) { + JTextArea jta = new JTextArea(info,8,20); + jta.setEditable(false); + jta.setLineWrap(true); + JScrollPane sp = new JScrollPane(jta); + return sp; + + } + + /* Main Method */ + + public static void main(String[] argv) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + PrintManualTest_FitWidthMultiple test = new PrintManualTest_FitWidthMultiple(latch); + Thread T1 = new Thread(test); + T1.start(); + + // wait for latch to complete + boolean ret = false; + try { + ret = latch.await(60, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + throw ie; + } + if (!ret) { + test.dispose(); + throw new RuntimeException(" User has not executed the test"); + } + if (test.testPassed == false) { + throw new RuntimeException("printed contents is beyond borders"); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java --- a/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -42,7 +42,7 @@ /** * @test - * @bug 8156217 + * @bug 8156217 8169922 * @key headful * @summary Selected text is shifted on HiDPI display * @run main FPMethodCalledTest diff -r 047a57b0839a -r 1c9922f121ff jdk/test/javax/xml/ws/8159058/SaajEmptyNamespaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/ws/8159058/SaajEmptyNamespaceTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8159058 + * @summary Test that empty default namespace declaration clears the + * default namespace value + * @modules java.xml.ws/com.sun.xml.internal.ws.api + * java.xml.ws/com.sun.xml.internal.ws.api.message.saaj + * java.xml.ws/com.sun.xml.internal.ws.message.stream + * @run testng/othervm SaajEmptyNamespaceTest + */ + +import com.sun.xml.internal.ws.api.SOAPVersion; +import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory; +import com.sun.xml.internal.ws.message.stream.StreamMessage; +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import javax.xml.namespace.QName; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.SOAPBody; +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.w3c.dom.Node; + +public class SaajEmptyNamespaceTest { + + /* + * Test that SOAP message with default namespace declaration that contains empty + * string is properly processed by SAAJ reader. + */ + @Test + public void testResetDefaultNamespaceSAAJ() throws Exception { + // Create SOAP message from XML string and process it with SAAJ reader + XMLStreamReader envelope = XMLInputFactory.newFactory().createXMLStreamReader( + new StringReader(INPUT_SOAP_MESSAGE)); + StreamMessage streamMessage = new StreamMessage(SOAPVersion.SOAP_11, + envelope, null); + SAAJFactory saajFact = new SAAJFactory(); + SOAPMessage soapMessage = saajFact.readAsSOAPMessage(SOAPVersion.SOAP_11, streamMessage); + + // Check if constructed object model meets local names and namespace expectations + SOAPElement request = (SOAPElement) soapMessage.getSOAPBody().getFirstChild(); + // Check top body element name + Assert.assertEquals(request.getLocalName(), "SampleServiceRequest"); + // Check top body element namespace + Assert.assertEquals(request.getNamespaceURI(), TEST_NS); + SOAPElement params = (SOAPElement) request.getFirstChild(); + // Check first child name + Assert.assertEquals(params.getLocalName(), "RequestParams"); + // Check if first child namespace is null + Assert.assertNull(params.getNamespaceURI()); + + // Check inner elements of the first child + SOAPElement param1 = (SOAPElement) params.getFirstChild(); + Assert.assertEquals(param1.getLocalName(), "Param1"); + Assert.assertNull(param1.getNamespaceURI()); + SOAPElement param2 = (SOAPElement) params.getChildNodes().item(1); + Assert.assertEquals(param2.getLocalName(), "Param2"); + Assert.assertNull(param2.getNamespaceURI()); + // Check full content of SOAP body + Assert.assertEquals(nodeToText(request), EXPECTED_RESULT); + } + + /* + * Test that adding element with explicitly null namespace URI shall put the + * element into global namespace. Namespace declarations are not added explicitly. + */ + @Test + public void testAddElementToNullNsNoDeclarations() throws Exception { + // Create empty SOAP message + SOAPMessage msg = createSoapMessage(); + SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); + + // Add elements + SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); + SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", null); + SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); + + // Check namespace URIs + Assert.assertNull(childGlobalNS.getNamespaceURI()); + Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); + } + + /* + * Test that adding element with explicitly empty namespace URI shall put + * the element into global namespace. Namespace declarations are not added + * explicitly. + */ + @Test + public void testAddElementToGlobalNsNoDeclarations() throws Exception { + // Create empty SOAP message + SOAPMessage msg = createSoapMessage(); + SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); + + // Add elements + SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); + SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", ""); + SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); + + // Check namespace URIs + Assert.assertNull(childGlobalNS.getNamespaceURI()); + Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); + } + + /* + * Test that adding element with explicitly empty namespace URI set via QName + * shall put the element into global namespace. + */ + @Test + public void testAddElementToNullNsQName() throws Exception { + // Create empty SOAP message + SOAPMessage msg = createSoapMessage(); + SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); + + // Add elements + SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); + parentExplicitNS.addNamespaceDeclaration("", TEST_NS); + SOAPElement childGlobalNS = parentExplicitNS.addChildElement(new QName(null, "global-child")); + childGlobalNS.addNamespaceDeclaration("", ""); + SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); + SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); + + // Check namespace URIs + Assert.assertNull(childGlobalNS.getNamespaceURI()); + Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); + Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); + } + + /* + * Test that adding element with explicitly empty namespace URI shall put + * the element into global namespace. + */ + @Test + public void testAddElementToGlobalNs() throws Exception { + // Create empty SOAP message + SOAPMessage msg = createSoapMessage(); + SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); + + // Add elements + SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); + parentExplicitNS.addNamespaceDeclaration("", TEST_NS); + SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", ""); + childGlobalNS.addNamespaceDeclaration("", ""); + SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); + SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); + + // Check namespace URIs + Assert.assertNull(childGlobalNS.getNamespaceURI()); + Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); + Assert.assertEquals(childDefaultNS.getNamespaceURI(), TEST_NS); + } + + /* + * Test that adding element with explicitly null namespace URI shall put + * the element into global namespace. + */ + @Test + public void testAddElementToNullNs() throws Exception { + // Create empty SOAP message + SOAPMessage msg = createSoapMessage(); + SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); + + // Add elements + SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); + parentExplicitNS.addNamespaceDeclaration("", TEST_NS); + SOAPElement childGlobalNS = parentExplicitNS.addChildElement("global-child", "", null); + childGlobalNS.addNamespaceDeclaration("", null); + SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); + SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); + + // Check namespace URIs + Assert.assertNull(childGlobalNS.getNamespaceURI()); + Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); + Assert.assertEquals(TEST_NS, childDefaultNS.getNamespaceURI()); + } + + /* + * Test that adding element with explicitly empty namespace URI via QName + * shall put the element in global namespace. + */ + @Test + public void testAddElementToGlobalNsQName() throws Exception { + // Create empty SOAP message + SOAPMessage msg = createSoapMessage(); + SOAPBody body = msg.getSOAPPart().getEnvelope().getBody(); + + // Add elements + SOAPElement parentExplicitNS = body.addChildElement("content", "", TEST_NS); + parentExplicitNS.addNamespaceDeclaration("", TEST_NS); + SOAPElement childGlobalNS = parentExplicitNS.addChildElement(new QName("", "global-child")); + childGlobalNS.addNamespaceDeclaration("", ""); + SOAPElement grandChildGlobalNS = childGlobalNS.addChildElement("global-grand-child"); + SOAPElement childDefaultNS = parentExplicitNS.addChildElement("default-child"); + + // Check namespace URIs + Assert.assertNull(childGlobalNS.getNamespaceURI()); + Assert.assertNull(grandChildGlobalNS.getNamespaceURI()); + Assert.assertEquals(childDefaultNS.getNamespaceURI(),TEST_NS); + } + + // Convert DOM node to text representation + private String nodeToText(Node node) throws TransformerException { + Transformer trans = TransformerFactory.newInstance().newTransformer(); + trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + trans.transform(new DOMSource(node), result); + String bodyContent = writer.toString(); + System.out.println("SOAP body content read by SAAJ:"+bodyContent); + return bodyContent; + } + + // Create SOAP message with empty body + private static SOAPMessage createSoapMessage() throws SOAPException, UnsupportedEncodingException { + String xml = "" + +""; + MessageFactory mFactory = MessageFactory.newInstance(); + SOAPMessage msg = mFactory.createMessage(); + msg.getSOAPPart().setContent(new StreamSource(new ByteArrayInputStream(xml.getBytes("utf-8")))); + return msg; + } + + // Namespace value used in tests + private static String TEST_NS = "http://example.org/test"; + + // Content of SOAP message passed to SAAJ factory + private static String INPUT_SOAP_MESSAGE = "" + + "" + + "" + + "" + + "" + + "hogehoge" + + "fugafuga" + + "" + + "" + + "" + + ""; + + // Expected body content after SAAJ processing + private static String EXPECTED_RESULT = "" + + "" + + "hogehoge" + + "fugafuga" + + "" + + ""; +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/lib/security/SecurityTools.java --- a/jdk/test/lib/security/SecurityTools.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +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. - */ - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import jdk.testlibrary.JDKToolLauncher; -import jdk.testlibrary.OutputAnalyzer; -import jdk.testlibrary.ProcessTools; - -public class SecurityTools { - - public static final String NO_ALIAS = null; - - // keytool - - public static OutputAnalyzer keytool(List options) - throws Throwable { - - JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("keytool") - .addVMArg("-Duser.language=en") - .addVMArg("-Duser.country=US"); - for (String option : options) { - if (option.startsWith("-J")) { - launcher.addVMArg(option.substring(2)); - } else { - launcher.addToolArg(option); - } - } - return ProcessTools.executeCommand(launcher.getCommand()); - } - - public static OutputAnalyzer keytool(String options) throws Throwable { - return keytool(options.split("\\s+")); - } - - public static OutputAnalyzer keytool(String... options) throws Throwable { - return keytool(List.of(options)); - } - - // jarsigner - - public static OutputAnalyzer jarsigner(String jar, String alias, - List options) throws Throwable { - JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner") - .addVMArg("-Duser.language=en") - .addVMArg("-Duser.country=US"); - for (String option : options) { - if (option.startsWith("-J")) { - launcher.addVMArg(option.substring(2)); - } else { - launcher.addToolArg(option); - } - } - launcher.addToolArg(jar); - if (alias != null) { - launcher.addToolArg(alias); - } - return ProcessTools.executeCommand(launcher.getCommand()); - } - - public static OutputAnalyzer jarsigner(String jar, String alias, - String options) throws Throwable { - - return jarsigner(jar, alias, options.split("\\s+")); - } - - public static OutputAnalyzer jarsigner(String jar, String alias, - String... options) throws Throwable { - - return jarsigner(jar, alias, List.of(options)); - } - - public static OutputAnalyzer sign(String jar, String alias, String... options) - throws Throwable { - - return jarsigner(jar, alias, - mergeOptions("-J-Djava.security.egd=file:/dev/./urandom", options)); - } - - public static OutputAnalyzer verify(String jar, String... options) - throws Throwable { - - return jarsigner(jar, NO_ALIAS, mergeOptions("-verify", options)); - } - - // helper methods - - private static List mergeOptions( - String firstOption, String... secondPart) { - - return mergeOptions(List.of(firstOption), secondPart); - } - - private static List mergeOptions( - List firstPart, String... secondPart) { - - List options = new ArrayList<>(firstPart); - Collections.addAll(options, secondPart); - return options; - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/net/www/protocol/http/SetIfModifiedSince.java --- a/jdk/test/sun/net/www/protocol/http/SetIfModifiedSince.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/net/www/protocol/http/SetIfModifiedSince.java Wed Jul 05 22:42:01 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - @bug 4213164 + @bug 4213164 8172253 @summary setIfModifiedSince mehtod in HttpURLConnection sometimes fails */ import java.util.*; @@ -88,7 +88,7 @@ //url = new URL(args[0]); url = new URL("http://localhost:" + String.valueOf(port) + "/anything"); - con = (HttpURLConnection)url.openConnection(); + con = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); con.setIfModifiedSince(date.getTime()); con.connect(); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java --- a/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary REGISTRY RegistryRunner + * @build TestLibrary RegistryVM RegistryRunner * @run main/othervm DeadCachedConnection */ @@ -100,7 +100,7 @@ public static int makeRegistry(int port) { try { - subreg = REGISTRY.createREGISTRY(System.out, System.err, "", port); + subreg = RegistryVM.createRegistryVM(System.out, System.err, "", port); subreg.start(); int regPort = subreg.getPort(); System.out.println("Starting registry on port " + regPort); @@ -113,11 +113,11 @@ return -1; } - private static REGISTRY subreg = null; + private static RegistryVM subreg = null; public static void killRegistry() throws InterruptedException { if (subreg != null) { - subreg.shutdown(); + subreg.cleanup(); subreg = null; } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/security/pkcs11/sslecc/CipherTest.java --- a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.security.*; import java.security.cert.*; -import java.security.cert.Certificate; import javax.net.ssl.*; @@ -61,6 +60,8 @@ private static PeerFactory peerFactory; + static final CountDownLatch clientCondition = new CountDownLatch(1); + static abstract class Server implements Runnable { final CipherTest cipherTest; @@ -313,6 +314,10 @@ } threads[i].start(); } + + // The client threads are ready. + clientCondition.countDown(); + try { for (int i = 0; i < THREADS; i++) { threads[i].join(); @@ -367,6 +372,10 @@ try { runTest(params); System.out.println("Passed " + params); + } catch (SocketTimeoutException ste) { + System.out.println("The client connects to the server timeout, " + + "so ignore the test."); + break; } catch (Exception e) { cipherTest.setFailed(); System.out.println("** Failed " + params + "**"); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/security/pkcs11/sslecc/JSSEClient.java --- a/jdk/test/sun/security/pkcs11/sslecc/JSSEClient.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/security/pkcs11/sslecc/JSSEClient.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * 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,10 +23,7 @@ import java.io.*; import java.net.*; -import java.util.*; -import java.security.*; -import java.security.cert.*; import java.security.cert.Certificate; import javax.net.ssl.*; @@ -46,10 +43,30 @@ SSLSocket socket = null; try { keyManager.setAuthType(params.clientAuth); - sslContext.init(new KeyManager[] {keyManager}, new TrustManager[] {cipherTest.trustManager}, cipherTest.secureRandom); - SSLSocketFactory factory = (SSLSocketFactory)sslContext.getSocketFactory(); - socket = (SSLSocket)factory.createSocket("127.0.0.1", cipherTest.serverPort); - socket.setSoTimeout(cipherTest.TIMEOUT); + sslContext.init( + new KeyManager[] { keyManager }, + new TrustManager[] { CipherTest.trustManager }, + CipherTest.secureRandom); + SSLSocketFactory factory + = (SSLSocketFactory) sslContext.getSocketFactory(); + + socket = (SSLSocket) factory.createSocket(); + try { + socket.connect(new InetSocketAddress("127.0.0.1", + CipherTest.serverPort), 15000); + } catch (IOException ioe) { + // The server side may be impacted by naughty test cases or + // third party routines, and cannot accept connections. + // + // Just ignore the test if the connection cannot be + // established. + System.out.println( + "Cannot make a connection in 15 seconds. " + + "Ignore in client side."); + return; + } + + socket.setSoTimeout(CipherTest.TIMEOUT); socket.setEnabledCipherSuites(new String[] {params.cipherSuite}); socket.setEnabledProtocols(new String[] {params.protocol}); InputStream in = socket.getInputStream(); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java --- a/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * 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,8 +24,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.SocketTimeoutException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; @@ -40,24 +43,37 @@ JSSEServer(CipherTest cipherTest) throws Exception { super(cipherTest); SSLContext serverContext = SSLContext.getInstance("TLS"); - serverContext.init(new KeyManager[] {cipherTest.keyManager}, new TrustManager[] {cipherTest.trustManager}, cipherTest.secureRandom); + serverContext.init( + new KeyManager[] { CipherTest.keyManager }, + new TrustManager[] { CipherTest.trustManager }, + CipherTest.secureRandom); SSLServerSocketFactory factory = (SSLServerSocketFactory)serverContext.getServerSocketFactory(); serverSocket = (SSLServerSocket)factory.createServerSocket(0); - cipherTest.serverPort = serverSocket.getLocalPort(); + serverSocket.setSoTimeout(CipherTest.TIMEOUT); + CipherTest.serverPort = serverSocket.getLocalPort(); serverSocket.setEnabledCipherSuites(factory.getSupportedCipherSuites()); serverSocket.setWantClientAuth(true); } @Override public void run() { - System.out.println("JSSE Server listening on port " + cipherTest.serverPort); + System.out.println("JSSE Server listening on port " + CipherTest.serverPort); Executor exec = Executors.newFixedThreadPool (CipherTest.THREADS, DaemonThreadFactory.INSTANCE); + try { + if (!CipherTest.clientCondition.await(CipherTest.TIMEOUT, + TimeUnit.MILLISECONDS)) { + System.out.println( + "The client is not the expected one or timeout. " + + "Ignore in server side."); + return; + } + while (true) { final SSLSocket socket = (SSLSocket)serverSocket.accept(); - socket.setSoTimeout(cipherTest.TIMEOUT); + socket.setSoTimeout(CipherTest.TIMEOUT); Runnable r = new Runnable() { @Override public void run() { @@ -86,11 +102,12 @@ }; exec.execute(r); } - } catch (IOException e) { + } catch (SocketTimeoutException ste) { + System.out.println("The server got timeout for waiting for the connection, " + + "so ignore the test."); + } catch (Exception e) { cipherTest.setFailed(); e.printStackTrace(); - // } } - } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/security/tools/keytool/PrintSSL.java --- a/jdk/test/sun/security/tools/keytool/PrintSSL.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/security/tools/keytool/PrintSSL.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. * 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,8 +25,7 @@ * @test * @bug 6480981 8160624 * @summary keytool should be able to import certificates from remote SSL server - * @library /lib/security - * @library /lib/testlibrary + * @library /test/lib * @run main/othervm PrintSSL */ @@ -36,7 +35,8 @@ import java.util.concurrent.CountDownLatch; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; -import jdk.testlibrary.OutputAnalyzer; +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; public class PrintSSL { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/sun/security/tools/keytool/ReadJar.java --- a/jdk/test/sun/security/tools/keytool/ReadJar.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/sun/security/tools/keytool/ReadJar.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,15 @@ * @test * @bug 6890872 8168882 * @summary keytool -printcert to recognize signed jar files - * @library /lib/security + * @library /test/lib * @library /lib/testlibrary */ import java.nio.file.Files; import java.nio.file.Paths; +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; import jdk.testlibrary.JarUtils; -import jdk.testlibrary.OutputAnalyzer; public class ReadJar { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/InputFilesTest.java --- a/jdk/test/tools/jar/InputFilesTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/tools/jar/InputFilesTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -102,6 +102,7 @@ "META-INF/MANIFEST.MF" + nl + "testfile1" + nl + "testfile2" + nl + + "META-INF/versions/9/" + nl + "META-INF/versions/9/testfile3" + nl + "META-INF/versions/9/testfile4" + nl; rm("test.jar test1 test2 test3 test4"); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/mmrjar/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/Basic.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8172432 + * @summary Fail to create a MR modular JAR with a versioned entry in + * base-versioned empty package + * @modules java.base/jdk.internal.module + * jdk.compiler + * jdk.jartool + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils + * @run testng Basic + */ + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Version; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Optional; +import java.util.Set; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipFile; + +import jdk.internal.module.ModuleInfoExtender; +import jdk.testlibrary.FileUtils; + +public class Basic { + 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 testsrc; + 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 Basic() throws IOException { + 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"); + + Set actual = lines(outbytes); + 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); + + String s = new String(errbytes.toByteArray()); + Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class")); + } + + // 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(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class")); + + jar("-tf mmr.jar"); + + Set actual = lines(outbytes); + 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(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class")); + } + + // 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(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class")); + + jar("-tf mmr.jar"); + + Set actual = lines(outbytes); + 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/", + "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); + } + + // jar tool does two updates, no exported packages, all concealed + @Test + public void test5() throws IOException { + // compile the mr10 directory + Path source = testsrc.resolve("src").resolve("mr10"); + Path destination = Paths.get("mr10"); + javac(source, destination); + + // create a directory for this tests special files + Files.createDirectory(Paths.get("test5")); + + // create an empty module-info.java + String hi = "module hi {" + linesep + "}" + linesep; + Path modinfo = Paths.get("test5", "module-info.java"); + Files.write(modinfo, hi.getBytes()); + + // and compile it + javac(modinfo, Paths.get("test5")); + + int rc = jar("--create --file mr.jar -C classes ."); + Assert.assertEquals(rc, 0); + + rc = jar("--update --file mr.jar -C test5 module-info.class" + + " --release 9 -C mr9 ."); + Assert.assertEquals(rc, 0); + + jar("tf mr.jar"); + + Set actual = lines(outbytes); + Set expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "p/", + "p/Hi.class", + "META-INF/versions/9/", + "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", + "module-info.class" + ); + Assert.assertEquals(actual, expected); + + jar("-d --file mr.jar"); + + actual = lines(outbytes); + expected = Set.of( + "hi", + "requires mandated java.base", + "contains p", + "contains p.internal" + ); + Assert.assertEquals(actual, expected); + + rc = jar("--update --file mr.jar --release 10 -C mr10 ."); + Assert.assertEquals(rc, 0); + + jar("tf mr.jar"); + + actual = lines(outbytes); + expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "p/", + "p/Hi.class", + "META-INF/versions/9/", + "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", + "META-INF/versions/10/", + "META-INF/versions/10/p/", + "META-INF/versions/10/p/internal/", + "META-INF/versions/10/p/internal/bar/", + "META-INF/versions/10/p/internal/bar/Gee.class", + "module-info.class" + ); + Assert.assertEquals(actual, expected); + + jar("-d --file mr.jar"); + + actual = lines(outbytes); + expected = Set.of( + "hi", + "requires mandated java.base", + "contains p", + "contains p.internal", + "contains p.internal.bar" + ); + Assert.assertEquals(actual, expected); + } + + // root and versioned module-info entries have different main-class, version + // attributes + @Test + public void test6() throws IOException { + // create a directory for this tests special files + Files.createDirectory(Paths.get("test6")); + Files.createDirectory(Paths.get("test6-v9")); + + // compile the classes directory + Path src = testsrc.resolve("src").resolve("classes"); + Path dst = Paths.get("test6"); + javac(src, dst); + + byte[] mdBytes = Files.readAllBytes(Paths.get("module-info.class")); + + ModuleInfoExtender mie = ModuleInfoExtender.newExtender( + new ByteArrayInputStream(mdBytes)); + + mie.mainClass("foo.main"); + mie.version(Version.parse("1.0")); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + mie.write(baos); + Files.write(Paths.get("test6", "module-info.class"), baos.toByteArray()); + Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray()); + + int rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 ."); + Assert.assertEquals(rc, 0); + + + // different main-class + mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes)); + mie.mainClass("foo.main2"); + mie.version(Version.parse("1.0")); + baos.reset(); + mie.write(baos); + Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray()); + + rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 ."); + Assert.assertEquals(rc, 1); + + Assert.assertTrue(Message.CONTAINS_DIFFERENT_MAINCLASS.match( + new String(errbytes.toByteArray()), + "META-INF/versions/9/module-info.class")); + + // different version + mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes)); + mie.mainClass("foo.main"); + mie.version(Version.parse("2.0")); + baos.reset(); + mie.write(baos); + Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray()); + + rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 ."); + Assert.assertEquals(rc, 1); + + Assert.assertTrue(Message.CONTAINS_DIFFERENT_VERSION.match( + new String(errbytes.toByteArray()), + "META-INF/versions/9/module-info.class")); + + } + + // versioned mmr without root module-info.class + @Test + public void test7() throws IOException { + // create a directory for this tests special files + Files.createDirectory(Paths.get("test7")); + Files.createDirectory(Paths.get("test7-v9")); + Files.createDirectory(Paths.get("test7-v10")); + + // compile the classes directory + Path src = testsrc.resolve("src").resolve("classes"); + Path dst = Paths.get("test7"); + javac(src, dst); + + // move module-info.class to v9 later use + Files.copy(Paths.get("module-info.class"), + Paths.get("test7-v9", "module-info.class")); + + Files.copy(Paths.get("test7-v9", "module-info.class"), + Paths.get("test7-v10", "module-info.class")); + + int rc = jar("--create --file mmr.jar --main-class=foo.main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 ."); + +System.out.println("-----------------------"); +System.out.println( new String(errbytes.toByteArray())); + + + Assert.assertEquals(rc, 0); + + + jar("-tf mmr.jar"); + +System.out.println("-----------------------"); +System.out.println( new String(outbytes.toByteArray())); + + Optional exp = Optional.of("foo.main"); + try (ZipFile zf = new ZipFile("mmr.jar")) { + Assert.assertTrue(zf.getEntry("module-info.class") == null); + + ModuleDescriptor md = ModuleDescriptor.read( + zf.getInputStream(zf.getEntry("META-INF/versions/9/module-info.class"))); + Assert.assertEquals(md.mainClass(), exp); + + md = ModuleDescriptor.read( + zf.getInputStream(zf.getEntry("META-INF/versions/10/module-info.class"))); + Assert.assertEquals(md.mainClass(), exp); + } + } + + private static Set lines(ByteArrayOutputStream baos) { + String s = new String(baos.toByteArray()); + return Arrays.stream(s.split("\\R")) + .map(l -> l.trim()) + .filter(l -> l.length() > 0) + .collect(Collectors.toSet()); + } + + static enum Message { + CONTAINS_DIFFERENT_MAINCLASS( + ": module-info.class in a versioned directory contains different \"main-class\"" + ), + CONTAINS_DIFFERENT_VERSION( + ": module-info.class in a versioned directory contains different \"version\"" + ), + NOT_FOUND_IN_BASE_ENTRY( + ", contains a new public class not found in base entries" + ), + NEW_CONCEALED_PACKAGE_WARNING( + " is a public class" + + " in a concealed package, placing this jar on the class path will result" + + " in incompatible public interfaces" + ); + + final String msg; + Message(String msg) { + this.msg = msg; + } + + /* + * Test if the given output contains this message ignoring the line break. + */ + boolean match(String output, String entry) { + System.out.println("Expected: " + entry + msg); + System.out.println("Found: " + output); + return Arrays.stream(output.split("\\R")) + .collect(Collectors.joining(" ")) + .contains(entry + msg); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/mmrjar/ConcealedPackage.java --- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,339 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8146486 - * @summary Fail to create a MR modular JAR with a versioned entry in - * base-versioned empty package - * @modules jdk.compiler - * jdk.jartool - * @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 testsrc; - 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 { - 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"); - - Set actual = lines(outbytes); - 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); - - String s = new String(errbytes.toByteArray()); - Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class")); - } - - // 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(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class")); - - jar("-tf mmr.jar"); - - Set actual = lines(outbytes); - 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(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class")); - } - - // 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(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class")); - - jar("-tf mmr.jar"); - - Set actual = lines(outbytes); - 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); - } - - // jar tool does two updates, no exported packages, all concealed - @Test - public void test5() throws IOException { - // compile the mr10 directory - Path source = testsrc.resolve("src").resolve("mr10"); - Path destination = Paths.get("mr10"); - javac(source, destination); - - // create a directory for this tests special files - Files.createDirectory(Paths.get("test5")); - - // create an empty module-info.java - String hi = "module hi {" + linesep + "}" + linesep; - Path modinfo = Paths.get("test5", "module-info.java"); - Files.write(modinfo, hi.getBytes()); - - // and compile it - javac(modinfo, Paths.get("test5")); - - int rc = jar("--create --file mr.jar -C classes ."); - Assert.assertEquals(rc, 0); - - rc = jar("--update --file mr.jar -C test5 module-info.class" - + " --release 9 -C mr9 ."); - Assert.assertEquals(rc, 0); - - jar("tf mr.jar"); - - Set actual = lines(outbytes); - Set expected = Set.of( - "META-INF/", - "META-INF/MANIFEST.MF", - "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", - "module-info.class" - ); - Assert.assertEquals(actual, expected); - - jar("-d --file mr.jar"); - - actual = lines(outbytes); - expected = Set.of( - "hi", - "requires mandated java.base", - "contains p", - "contains p.internal" - ); - Assert.assertEquals(actual, expected); - - rc = jar("--update --file mr.jar --release 10 -C mr10 ."); - Assert.assertEquals(rc, 0); - - jar("tf mr.jar"); - - actual = lines(outbytes); - expected = Set.of( - "META-INF/", - "META-INF/MANIFEST.MF", - "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", - "META-INF/versions/10/p/", - "META-INF/versions/10/p/internal/", - "META-INF/versions/10/p/internal/bar/", - "META-INF/versions/10/p/internal/bar/Gee.class", - "module-info.class" - ); - Assert.assertEquals(actual, expected); - - jar("-d --file mr.jar"); - - actual = lines(outbytes); - expected = Set.of( - "hi", - "requires mandated java.base", - "contains p", - "contains p.internal", - "contains p.internal.bar" - ); - Assert.assertEquals(actual, expected); - } - - private static Set lines(ByteArrayOutputStream baos) { - String s = new String(baos.toByteArray()); - return Arrays.stream(s.split("\\R")) - .map(l -> l.trim()) - .filter(l -> l.length() > 0) - .collect(Collectors.toSet()); - } - - static enum Message { - NOT_FOUND_IN_BASE_ENTRY( - ", contains a new public class not found in base entries" - ), - NEW_CONCEALED_PACKAGE_WARNING( - " is a public class" + - " in a concealed package, placing this jar on the class path will result" + - " in incompatible public interfaces" - ); - - final String msg; - Message(String msg) { - this.msg = msg; - } - - /* - * Test if the given output contains this message ignoring the line break. - */ - boolean match(String output, String entry) { - System.out.println("Expected: " + entry + msg); - System.out.println("Found: " + output); - return Arrays.stream(output.split("\\R")) - .collect(Collectors.joining(" ")) - .contains(entry + msg); - } - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/modularJar/Basic.java --- a/jdk/test/tools/jar/modularJar/Basic.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/tools/jar/modularJar/Basic.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ /* * @test - * @bug 8167328 + * @bug 8167328 8171830 * @library /lib/testlibrary * @modules jdk.compiler * jdk.jartool @@ -241,6 +241,11 @@ java(mp, FOO.moduleName + "/" + FOO.mainClass) .assertSuccess() +.resultChecker(r -> { + System.out.println("==================================="); + System.out.println(r.output); + System.out.println("==================================="); +}) .resultChecker(r -> assertModuleData(r, FOO)); try (InputStream fis = Files.newInputStream(modularJar); JarInputStream jis = new JarInputStream(fis)) { @@ -417,6 +422,7 @@ jar("--update", "--file=" + modularJar.toString(), "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, "-m", mrjarDir.resolve("META-INF/MANIFEST.MF").toRealPath().toString(), "-C", mrjarDir.toString(), "META-INF/versions/9/module-info.class") .assertSuccess(); @@ -734,6 +740,25 @@ } @Test + public void exportCreateWithMissingPkg() throws IOException { + + Path foobar = TEST_SRC.resolve("src").resolve("foobar"); + Path dst = Files.createDirectories(MODULE_CLASSES.resolve("foobar")); + javac(dst, null, sourceList(foobar)); + + Path mp = Paths.get("exportWithMissingPkg"); + createTestDir(mp); + Path modClasses = dst; + Path modularJar = mp.resolve("foofoo.jar"); + + jar("--create", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "module-info.class", + "-C", modClasses.toString(), "jdk/test/foo/Foo.class") + .assertFailure(); + } + + @Test public void printModuleDescriptorFoo() throws IOException { Path mp = Paths.get("printModuleDescriptorFoo"); createTestDir(mp); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/modularJar/src/foobar/Bar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/modularJar/src/foobar/Bar.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.bar; + +public class Bar { + public static void main(String[] args) {} +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/modularJar/src/foobar/Foo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/modularJar/src/foobar/Foo.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.foo; + +public class Foo { + public static void main(String[] args) {} +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/modularJar/src/foobar/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/modularJar/src/foobar/module-info.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 foo { + exports jdk.test.foo; + exports jdk.test.bar; + opens jdk.test.foo; + opens jdk.test.bar; +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/Basic1.java --- a/jdk/test/tools/jar/multiRelease/Basic1.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/tools/jar/multiRelease/Basic1.java Wed Jul 05 22:42:01 2017 +0200 @@ -62,15 +62,20 @@ Path source = Paths.get(src, "data", test, "base", "version"); javac(classes, source.resolve("Main.java"), source.resolve("Version.java")); - Path v9 = Paths.get("v9").resolve("META-INF").resolve("versions").resolve("9"); + Path v9 = Paths.get("v9"); Files.createDirectories(v9); source = Paths.get(src, "data", test, "v9", "version"); javac(v9, source.resolve("Version.java")); - Path v10 = Paths.get("v10").resolve("META-INF").resolve("versions").resolve("10"); + Path v10 = Paths.get("v10"); Files.createDirectories(v10); source = Paths.get(src, "data", test, "v10", "version"); javac(v10, source.resolve("Version.java")); + + Path v10_1 = Paths.get("v10_1").resolve("META-INF").resolve("versions").resolve("v10"); + Files.createDirectories(v10_1); + source = Paths.get(src, "data", test, "v10", "version"); + javac(v10_1, source.resolve("Version.java")); } @Test @@ -95,28 +100,30 @@ new String[] {"classes", "base", "version", "Version.class"}, "META-INF/versions/9/version/Version.class", - new String[] {"v9", "META-INF", "versions", "9", "version", "Version.class"}, + new String[] {"v9", "version", "Version.class"}, "META-INF/versions/10/version/Version.class", - new String[] {"v10", "META-INF", "versions", "10", "version", "Version.class"} + new String[] {"v10", "version", "Version.class"} ); compare(jarfile, names); } + @Test public void testFail() throws IOException { String jarfile = "test.jar"; Path classes = Paths.get("classes"); - Path v9 = Paths.get("v9"); - Path v10 = Paths.get("v10"); + Path v10 = Paths.get("v10_1"); jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".", - "--release", "9", "-C", v10.toString(), ".") + "--release", "10", "-C", v10.toString(), ".") .assertFailure() .outputContains("unexpected versioned entry META-INF/versions/"); } + + private void checkMultiRelease(String jarFile, boolean expected) throws IOException { try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ, JarFile.runtimeVersion())) { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/RuntimeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/RuntimeTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,236 @@ +/* + * 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 + * @summary Test Multi-Release jar usage in runtime + * @library /test/lib + * @library /lib/testlibrary + * @modules jdk.compiler + * @build jdk.test.lib.JDKToolFinder jdk.test.lib.JDKToolLauncher + * jdk.test.lib.process.OutputAnalyzer + * jdk.test.lib.process.ProcessTools + * CompilerUtils RuntimeTest + * @run testng RuntimeTest + */ + +import static org.testng.Assert.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +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.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class RuntimeTest { + public static final int SUCCESS = 0; + private final String src = System.getProperty("test.src", "."); + private final String usr = System.getProperty("user.dir", "."); + + @DataProvider(name = "jarFiles") + Object[][] jarFiles() { + return new Object[][] { { "MV_BOTH.jar", 9, 9, 9 }, + { "MV_ONLY_9.jar", 9, 9, 9 }, + { "NON_MV.jar", 8, 8, 8 } }; + } + + @BeforeClass + protected void setUpTest() throws Throwable { + compile(); + Path classes = Paths.get("classes"); + jar("cfm", "MV_BOTH.jar", "manifest.txt", + "-C", classes.resolve("base").toString(), ".", + "--release", "9", "-C", classes.resolve("v9").toString(), ".", + "--release", "10", "-C", classes.resolve("v10").toString(), ".") + .shouldHaveExitValue(0); + + jar("cfm", "MV_ONLY_9.jar", "manifest.txt", + "-C", classes.resolve("base").toString(), ".", + "--release", "9", "-C", classes.resolve("v9").toString(), ".") + .shouldHaveExitValue(0); + jar("cfm", "NON_MV.jar", "manifest.txt", + "-C", classes.resolve("base").toString(), ".") + .shouldHaveExitValue(0); + } + + @Test(dataProvider = "jarFiles") + public void testClasspath(String jar, int mainVer, int helperVer, + int resVer) throws Throwable { + String[] command = { "-cp", jar, "testpackage.Main" }; + System.out.println("Command arguments:" + Arrays.asList(command)); + System.out.println(); + java(command).shouldHaveExitValue(SUCCESS) + .shouldContain("Main version: " + mainVer) + .shouldContain("Helpers version: " + helperVer) + .shouldContain("Resource version: " + resVer); + } + + @Test(dataProvider = "jarFiles") + void testMVJarAsLib(String jar, int mainVer, int helperVer, int resVer) + throws Throwable { + String[] apps = { "UseByImport", "UseByReflection" }; + for (String app : apps) { + String[] command = {"-cp", + jar + File.pathSeparatorChar + "classes/test/", app }; + System.out.println("Command arguments:" + Arrays.asList(command)); + System.out.println(); + java(command).shouldHaveExitValue(SUCCESS) + .shouldContain("Main version: " + mainVer) + .shouldContain("Helpers version: " + helperVer) + .shouldContain("Resource version: " + resVer); + } + } + + @Test(dataProvider = "jarFiles") + void testJavaJar(String jar, int mainVer, int helperVer, int resVer) + throws Throwable { + String[] command = { "-jar", jar }; + System.out.println("Command arguments:" + Arrays.asList(command)); + System.out.println(); + java(command).shouldHaveExitValue(SUCCESS) + .shouldContain("Main version: " + mainVer) + .shouldContain("Helpers version: " + helperVer) + .shouldContain("Resource version: " + resVer); + } + + @Test(dataProvider = "jarFiles") + void testURLClassLoader(String jarName, int mainVer, int helperVer, + int resVer) throws ClassNotFoundException, NoSuchMethodException, + IllegalAccessException, IllegalArgumentException, + InvocationTargetException, IOException { + Path pathToJAR = Paths.get(jarName).toAbsolutePath(); + URL jarURL1 = new URL("jar:file:" + pathToJAR + "!/"); + URL jarURL2 = new URL("file:///" + pathToJAR); + testURLClassLoaderURL(jarURL1, mainVer, helperVer, resVer); + testURLClassLoaderURL(jarURL2, mainVer, helperVer, resVer); + } + + private static void testURLClassLoaderURL(URL jarURL, + int mainVersionExpected, int helperVersionExpected, + int resourceVersionExpected) throws ClassNotFoundException, + NoSuchMethodException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException, IOException { + System.out.println( + "Testing URLClassLoader MV JAR support for URL: " + jarURL); + URL[] urls = { jarURL }; + int mainVersionActual; + int helperVersionActual; + int resourceVersionActual; + try (URLClassLoader cl = URLClassLoader.newInstance(urls)) { + Class c = cl.loadClass("testpackage.Main"); + Method getMainVersion = c.getMethod("getMainVersion"); + mainVersionActual = (int) getMainVersion.invoke(null); + Method getHelperVersion = c.getMethod("getHelperVersion"); + helperVersionActual = (int) getHelperVersion.invoke(null); + try (InputStream ris = cl.getResourceAsStream("versionResource"); + BufferedReader br = new BufferedReader( + new InputStreamReader(ris))) { + resourceVersionActual = Integer.parseInt(br.readLine()); + } + } + + assertEquals(mainVersionActual, mainVersionExpected, + "Test failed: Expected Main class version: " + + mainVersionExpected + " Actual version: " + + mainVersionActual); + assertEquals(helperVersionActual, helperVersionExpected, + "Test failed: Expected Helper class version: " + + helperVersionExpected + " Actual version: " + + helperVersionActual); + assertEquals(resourceVersionActual, resourceVersionExpected, + "Test failed: Expected resource version: " + + resourceVersionExpected + " Actual version: " + + resourceVersionActual); + } + + @Test(dataProvider = "jarFiles") + void testJjs(String jar, int mainVer, int helperVer, int resVer) + throws Throwable { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jjs"); + launcher.addToolArg("-cp").addToolArg(jar) + .addToolArg(src + "/data/runtimetest/MVJarJJSTestScript.js"); + ProcessTools.executeCommand(launcher.getCommand()) + .shouldHaveExitValue(SUCCESS) + .shouldContain("Main version: " + mainVer) + .shouldContain("Helpers version: " + helperVer) + .shouldContain("Resource version: " + resVer); + } + + private static OutputAnalyzer jar(String... args) throws Throwable { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jar"); + Stream.of(args).forEach(launcher::addToolArg); + return ProcessTools.executeCommand(launcher.getCommand()); + } + + private void compile() throws Throwable { + String[] vers = { "base", "v9", "v10" }; + for (String ver : vers) { + Path classes = Paths.get(usr, "classes", ver); + Files.createDirectories(classes); + Path source = Paths.get(src, "data", "runtimetest", ver); + assertTrue(CompilerUtils.compile(source, classes)); + Files.copy(source.resolve("versionResource"), + classes.resolve("versionResource"), + StandardCopyOption.REPLACE_EXISTING); + } + + Path classes = Paths.get(usr, "classes", "test"); + Files.createDirectory(classes); + Path source = Paths.get(src, "data", "runtimetest", "test"); + assertTrue( + CompilerUtils.compile(source, classes, "-cp", "classes/base/")); + Files.copy(Paths.get(src, "data", "runtimetest", "manifest.txt"), + Paths.get(usr, "manifest.txt"), + StandardCopyOption.REPLACE_EXISTING); + } + + OutputAnalyzer java(String... args) throws Throwable { + String java = JDKToolFinder.getJDKTool("java"); + + List commands = new ArrayList<>(); + commands.add(java); + Stream.of(args).forEach(x -> commands.add(x)); + return ProcessTools.executeCommand(new ProcessBuilder(commands)); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/MVJarJJSTestScript.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/MVJarJJSTestScript.js Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +var Main = Java.type("testpackage.Main"); +var mainVersion = Main.getMainVersion(); +var helperVersion = Main.getHelperVersion(); +var resourceVersion = Main.getResourceVersion(); +print("Main version: " + mainVersion); +print("Helpers version: " + helperVersion); +print("Resource version: " + resourceVersion); diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/base/testpackage/Helper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/base/testpackage/Helper.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 testpackage; + +public class Helper { + + private static final int HELPER_VERSION = 8; + + public static int getHelperVersion() { + return HELPER_VERSION; + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/base/testpackage/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/base/testpackage/Main.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,62 @@ +/* + * 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 testpackage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class Main { + + private static final int MAIN_VERSION = 8; + + public static void main(String[] args) { + System.out.println("Main version: " + getMainVersion()); + System.out.println("Helpers version: " + getHelperVersion()); + System.out.println("Resource version: " + getResourceVersion()); + } + + public static int getMainVersion() { + return MAIN_VERSION; + } + + public static int getHelperVersion() { + return testpackage.Helper.getHelperVersion(); + } + + public static int getResourceVersion() { + ClassLoader cl = Main.class.getClassLoader(); + InputStream ris = cl.getResourceAsStream("versionResource"); + if (ris == null) { + throw new Error("Test issue: resource versionResource" + + " cannot be loaded!"); + } + try (BufferedReader br = new BufferedReader(new InputStreamReader(ris))) { + return Integer.parseInt(br.readLine()); + } catch (IOException ioe) { + throw new Error("Unexpected issue", ioe); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/base/versionResource --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/base/versionResource Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,1 @@ +8 \ No newline at end of file diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/manifest.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/manifest.txt Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,1 @@ +Main-Class: testpackage.Main diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/test/UseByImport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/test/UseByImport.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 testpackage.Main; + +/** + * This class is used in MVJarAsLibraryTest.java test. + * It is a part of the test. + */ +public class UseByImport { + + /** + * Method for the test execution. + * @param args - no args needed + */ + public static void main(String[] args) { + System.out.println("Main version: " + Main.getMainVersion()); + System.out.println("Helpers version: " + Main.getHelperVersion()); + System.out.println("Resource version: " + Main.getResourceVersion()); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/test/UseByReflection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/test/UseByReflection.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,64 @@ +/* + * 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.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * This class is used in RuntimeTest.java. + */ +public class UseByReflection { + + /** + * Method for the test execution. + * + * @param args - no args needed + * @throws java.lang.ClassNotFoundException + * @throws java.lang.NoSuchMethodException + * @throws java.lang.IllegalAccessException + * @throws java.lang.reflect.InvocationTargetException + * @throws java.io.IOException + */ + public static void main(String[] args) throws ClassNotFoundException, + NoSuchMethodException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException, IOException { + Class mainClass = Class.forName("testpackage.Main"); + Method getMainVersion = mainClass.getMethod("getMainVersion"); + int mainVersionActual = (int) getMainVersion.invoke(null); + Method getHelperVersion = mainClass.getMethod("getHelperVersion"); + int helperVersionActual = (int) getHelperVersion.invoke(null); + ClassLoader cl = UseByReflection.class.getClassLoader(); + int resourceVersionActual; + try (InputStream ris = cl.getResourceAsStream("versionResource"); + BufferedReader br = new BufferedReader(new InputStreamReader(ris))) { + resourceVersionActual = Integer.parseInt(br.readLine()); + } + System.out.println("Main version: " + mainVersionActual); + System.out.println("Helpers version: " + helperVersionActual); + System.out.println("Resource version: " + resourceVersionActual); + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/v10/testpackage/Helper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/v10/testpackage/Helper.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 testpackage; + +public class Helper { + + private static final int HELPER_VERSION = 10; + + public static int getHelperVersion() { + return HELPER_VERSION; + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/v10/testpackage/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/v10/testpackage/Main.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,62 @@ +/* + * 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 testpackage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class Main { + + private static final int MAIN_VERSION = 10; + + public static void main(String[] args) { + System.out.println("Main version: " + getMainVersion()); + System.out.println("Helpers version: " + getHelperVersion()); + System.out.println("Resource version: " + getResourceVersion()); + } + + public static int getMainVersion() { + return MAIN_VERSION; + } + + public static int getHelperVersion() { + return testpackage.Helper.getHelperVersion(); + } + + public static int getResourceVersion() { + ClassLoader cl = Main.class.getClassLoader(); + InputStream ris = cl.getResourceAsStream("versionResource"); + if (ris == null) { + throw new Error("Test issue: resource versionResource" + + " cannot be loaded!"); + } + try (BufferedReader br = new BufferedReader(new InputStreamReader(ris))) { + return Integer.parseInt(br.readLine()); + } catch (IOException ioe) { + throw new Error("Unexpected issue", ioe); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/v10/versionResource --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/v10/versionResource Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,1 @@ +10 diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/v9/testpackage/Helper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/v9/testpackage/Helper.java Wed Jul 05 22:42:01 2017 +0200 @@ -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 testpackage; + +public class Helper { + + private static final int HELPER_VERSION = 9; + + public static int getHelperVersion() { + return HELPER_VERSION; + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/v9/testpackage/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/v9/testpackage/Main.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,62 @@ +/* + * 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 testpackage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class Main { + + private static final int MAIN_VERSION = 9; + + public static void main(String[] args) { + System.out.println("Main version: " + getMainVersion()); + System.out.println("Helpers version: " + getHelperVersion()); + System.out.println("Resource version: " + getResourceVersion()); + } + + public static int getMainVersion() { + return MAIN_VERSION; + } + + public static int getHelperVersion() { + return testpackage.Helper.getHelperVersion(); + } + + public static int getResourceVersion() { + ClassLoader cl = Main.class.getClassLoader(); + InputStream ris = cl.getResourceAsStream("versionResource"); + if (ris == null) { + throw new Error("Test issue: resource versionResource" + + " cannot be loaded!"); + } + try (BufferedReader br = new BufferedReader(new InputStreamReader(ris))) { + return Integer.parseInt(br.readLine()); + } catch (IOException ioe) { + throw new Error("Unexpected issue", ioe); + } + } +} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jar/multiRelease/data/runtimetest/v9/versionResource --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/data/runtimetest/v9/versionResource Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,1 @@ +9 diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/JmodTest.java --- a/jdk/test/tools/jmod/JmodTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/tools/jmod/JmodTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 8142968 8166568 8166286 8170618 + * @bug 8142968 8166568 8166286 8170618 8168149 * @summary Basic test for jmod * @library /lib/testlibrary * @modules jdk.compiler @@ -459,6 +459,76 @@ } @Test + public void testLastOneWins() throws IOException { + Path workDir = Paths.get("lastOneWins"); + if (Files.exists(workDir)) + FileUtils.deleteFileTreeWithRetry(workDir); + Files.createDirectory(workDir); + Path jmod = MODS_DIR.resolve("lastOneWins.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); + Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); + Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); + Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); + + Path shouldNotBeAdded = workDir.resolve("shouldNotBeAdded"); + Files.createDirectory(shouldNotBeAdded); + Files.write(shouldNotBeAdded.resolve("aFile"), "hello".getBytes(UTF_8)); + + // Pairs of options. For options with required arguments the last one + // should win ( first should be effectively ignored, but may still be + // validated ). + jmod("create", + "--conf", shouldNotBeAdded.toString(), + "--conf", cf.toString(), + "--cmds", shouldNotBeAdded.toString(), + "--cmds", bp.toString(), + "--libs", shouldNotBeAdded.toString(), + "--libs", lp.toString(), + "--class-path", shouldNotBeAdded.toString(), + "--class-path", cp.toString(), + "--main-class", "does.NotExist", + "--main-class", "jdk.test.foo.Foo", + "--module-version", "00001", + "--module-version", "5.4.3", + "--do-not-resolve-by-default", + "--do-not-resolve-by-default", + "--warn-if-resolved=incubating", + "--warn-if-resolved=deprecated", + MODS_DIR.resolve("lastOneWins.jmod").toString()) + .assertSuccess() + .resultChecker(r -> { + ModuleDescriptor md = getModuleDescriptor(jmod); + Optional omc = md.mainClass(); + assertTrue(omc.isPresent()); + assertEquals(omc.get(), "jdk.test.foo.Foo"); + Optional ov = md.version(); + assertTrue(ov.isPresent()); + assertEquals(ov.get().toString(), "5.4.3"); + + try (Stream s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); + Stream s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p); + Stream s3 = findFiles(bp).map(p -> CMDS_PREFIX + p); + Stream s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) { + Set expectedFilenames = Stream.concat(Stream.concat(s1,s2), + Stream.concat(s3, s4)) + .collect(toSet()); + assertJmodContent(jmod, expectedFilenames); + } + }); + + jmod("extract", + "--dir", "blah", + "--dir", "lastOneWinsExtractDir", + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + assertTrue(Files.exists(Paths.get("lastOneWinsExtractDir"))); + assertTrue(Files.notExists(Paths.get("blah"))); + }); + } + + @Test public void testPackagesAttribute() throws IOException { Path jmod = MODS_DIR.resolve("foo.jmod"); FileUtils.deleteFileIfExistsWithRetry(jmod); @@ -510,36 +580,24 @@ } @Test - public void testTmpFileAlreadyExists() throws IOException { - // Implementation detail: jmod tool creates .tmp - // Ensure that there are no problems if existing - - Path jmod = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod"); - Path tmp = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod.tmp"); - FileUtils.deleteFileIfExistsWithRetry(jmod); - FileUtils.deleteFileIfExistsWithRetry(tmp); - Files.createFile(tmp); - String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); - - jmod("create", - "--class-path", cp, - jmod.toString()) - .assertSuccess() - .resultChecker(r -> - assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp) - ); - } - - @Test public void testTmpFileRemoved() throws IOException { // Implementation detail: jmod tool creates .tmp // Ensure that it is removed in the event of a failure. // The failure in this case is a class in the unnamed package. - Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod"); - Path tmp = MODS_DIR.resolve("testTmpFileRemoved.jmod.tmp"); + String filename = "testTmpFileRemoved.jmod"; + Path jmod = MODS_DIR.resolve(filename); + + // clean up files FileUtils.deleteFileIfExistsWithRetry(jmod); - FileUtils.deleteFileIfExistsWithRetry(tmp); + findTmpFiles(filename).forEach(tmp -> { + try { + FileUtils.deleteFileIfExistsWithRetry(tmp); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator + EXPLODED_DIR.resolve("foo").resolve("classes") .resolve("jdk").resolve("test").resolve("foo").toString(); @@ -550,10 +608,22 @@ .assertFailure() .resultChecker(r -> { assertContains(r.output, "unnamed package"); - assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp); + Set tmpfiles = findTmpFiles(filename).collect(toSet()); + assertTrue(tmpfiles.isEmpty(), "Unexpected tmp file:" + tmpfiles); }); } + private Stream findTmpFiles(String prefix) { + try { + Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir")); + return Files.find(tmpdir, 1, (p, attrs) -> + p.getFileName().toString().startsWith(prefix) + && p.getFileName().toString().endsWith(".tmp")); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + // --- static boolean compileModule(String name, Path dest) throws IOException { diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/HashesTest.java --- a/jdk/test/tools/jmod/hashes/HashesTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/jdk/test/tools/jmod/hashes/HashesTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,19 +23,22 @@ /* * @test + * @bug 8160286 * @summary Test the recording and checking of module hashes - * @author Andrei Eremeev * @library /lib/testlibrary * @modules java.base/jdk.internal.misc * java.base/jdk.internal.module + * jdk.compiler + * jdk.jartool * jdk.jlink - * jdk.compiler - * @build CompilerUtils + * @build CompilerUtils ModuleInfoMaker * @run testng HashesTest */ +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; @@ -53,109 +56,311 @@ import java.util.Set; import java.util.spi.ToolProvider; import java.util.stream.Collectors; +import java.util.stream.Stream; import jdk.internal.module.ModuleInfo; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModulePath; -import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import static org.testng.Assert.*; +import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; public class HashesTest { static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") .orElseThrow(() -> new RuntimeException("jmod tool not found") ); + static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); - private final Path testSrc = Paths.get(System.getProperty("test.src")); - private final Path modSrc = testSrc.resolve("src"); - private final Path mods = Paths.get("mods"); - private final Path jmods = Paths.get("jmods"); - private final String[] modules = new String[] { "m1", "m2", "m3"}; + private final Path mods; + private final Path srcDir; + private final Path lib; + private final ModuleInfoMaker builder; + HashesTest(Path dest) throws IOException { + if (Files.exists(dest)) { + deleteDirectory(dest); + } + this.mods = dest.resolve("mods"); + this.srcDir = dest.resolve("src"); + this.lib = dest.resolve("lib"); + this.builder = new ModuleInfoMaker(srcDir); + + Files.createDirectories(lib); + Files.createDirectories(mods); + } + + @Test + public static void test() throws IOException { + Path dest = Paths.get("test"); + HashesTest ht = new HashesTest(dest); - @BeforeTest - private void setup() throws Exception { - if (Files.exists(jmods)) { - deleteDirectory(jmods); - } - Files.createDirectories(jmods); + // create modules for test cases + ht.makeModule("m2"); + ht.makeModule("m3"); + ht.makeModule("m1", "m2", "m3"); + + ht.makeModule("org.bar", TRANSITIVE, "m1"); + ht.makeModule("org.foo", TRANSITIVE, "org.bar"); + + // create JMOD for m1, m2, m3 + ht.makeJmod("m2"); + ht.makeJmod("m3"); + + // no hash is recorded since m1 has outgoing edges + ht.jmodHashModules("m1", ".*"); + + // no hash is recorded in m1, m2, m3 + assertTrue(ht.hashes("m1") == null); + assertTrue(ht.hashes("m2") == null); + assertTrue(ht.hashes("m3") == null); + + // hash m1 in m2 + ht.jmodHashModules("m2", "m1"); + ht.checkHashes("m2", "m1"); + + // hash m1 in m2 + ht.jmodHashModules("m2", ".*"); + ht.checkHashes("m2", "m1"); - // build m2, m3 required by m1 - compileModule("m2", modSrc); - jmod("m2"); + // create m2.jmod with no hash + ht.makeJmod("m2"); + // run jmod hash command to hash m1 in m2 and m3 + runJmod(List.of("hash", "--module-path", ht.lib.toString(), + "--hash-modules", ".*")); + ht.checkHashes("m2", "m1"); + ht.checkHashes("m3", "m1"); + + // check transitive requires + ht.makeJmod("org.bar"); + ht.makeJmod("org.foo"); - compileModule("m3", modSrc); - jmod("m3"); + ht.jmodHashModules("org.bar", "org.*"); + ht.checkHashes("org.bar", "org.foo"); + + ht.jmodHashModules( "m3", ".*"); + ht.checkHashes("m3", "org.foo", "org.bar", "m1"); + } + + @Test + public static void multiBaseModules() throws IOException { + Path dest = Paths.get("test2"); + HashesTest ht = new HashesTest(dest); - // build m1 - compileModule("m1", modSrc); - // no hash is recorded since m1 has outgoing edges - jmod("m1", "--module-path", jmods.toString(), "--hash-modules", ".*"); + /* + * y2 -----------> y1 + * |______ + * | | + * V V + * z3 -> z2 + * | | + * | V + * |---> z1 + */ + + ht.makeModule("z1"); + ht.makeModule("z2", "z1"); + ht.makeModule("z3", "z1", "z2"); + + ht.makeModule("y1"); + ht.makeModule("y2", "y1", "z2", "z3"); - // compile org.bar and org.foo - compileModule("org.bar", modSrc); - compileModule("org.foo", modSrc); + Set ys = Set.of("y1", "y2"); + Set zs = Set.of("z1", "z2", "z3"); + + // create JMOD files + Stream.concat(ys.stream(), zs.stream()).forEach(ht::makeJmod); + + // run jmod hash command + runJmod(List.of("hash", "--module-path", ht.lib.toString(), + "--hash-modules", ".*")); + + /* + * z1 and y1 are the modules with hashes recorded. + */ + ht.checkHashes("y1", "y2"); + ht.checkHashes("z1", "z2", "z3", "y2"); + Stream.concat(ys.stream(), zs.stream()) + .filter(mn -> !mn.equals("y1") && !mn.equals("z1")) + .forEach(mn -> assertTrue(ht.hashes(mn) == null)); } @Test - public void test() throws Exception { - for (String mn : modules) { - assertTrue(hashes(mn) == null); + public static void mixJmodAndJarFile() throws IOException { + Path dest = Paths.get("test3"); + HashesTest ht = new HashesTest(dest); + + /* + * j3 -----------> j2 + * |______ + * | | + * V V + * m3 -> m2 + * | | + * | V + * |---> m1 -> j1 -> jdk.jlink + */ + + ht.makeModule("j1"); + ht.makeModule("j2"); + ht.makeModule("m1", "j1"); + ht.makeModule("m2", "m1"); + ht.makeModule("m3", "m1", "m2"); + + ht.makeModule("j3", "j2", "m2", "m3"); + + Set jars = Set.of("j1", "j2", "j3"); + Set jmods = Set.of("m1", "m2", "m3"); + + // create JMOD and JAR files + jars.forEach(ht::makeJar); + jmods.forEach(ht::makeJmod); + + // run jmod hash command + runJmod(List.of("hash", "--module-path", ht.lib.toString(), + "--hash-modules", "^j.*|^m.*")); + + /* + * j1 and j2 are the modules with hashes recorded. + */ + ht.checkHashes("j2", "j3"); + ht.checkHashes("j1", "m1", "m2", "m3", "j3"); + Stream.concat(jars.stream(), jmods.stream()) + .filter(mn -> !mn.equals("j1") && !mn.equals("j2")) + .forEach(mn -> assertTrue(ht.hashes(mn) == null)); + } + + @Test + public static void upgradeableModule() throws IOException { + Path mpath = Paths.get(System.getProperty("java.home"), "jmods"); + if (!Files.exists(mpath)) { + return; } - // hash m1 in m2 - jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1"); - checkHashes(hashes("m2"), "m1"); - - // hash m1 in m2 - jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*"); - checkHashes(hashes("m2"), "m1"); + Path dest = Paths.get("test4"); + HashesTest ht = new HashesTest(dest); + ht.makeModule("m1"); + ht.makeModule("java.xml.bind", "m1"); + ht.makeModule("java.xml.ws", "java.xml.bind"); + ht.makeModule("m2", "java.xml.ws"); - // create m2.jmod with no hash - jmod("m2"); - // run jmod hash command to hash m1 in m2 and m3 - runJmod(Arrays.asList("hash", "--module-path", jmods.toString(), - "--hash-modules", ".*")); - checkHashes(hashes("m2"), "m1"); - checkHashes(hashes("m3"), "m1"); + ht.makeJmod("m1"); + ht.makeJmod("m2"); + ht.makeJmod("java.xml.ws"); + ht.makeJmod("java.xml.bind", + "--module-path", + ht.lib.toString() + File.pathSeparator + mpath, + "--hash-modules", "^java.xml.*|^m.*"); - jmod("org.bar"); - jmod("org.foo"); - - jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*"); - checkHashes(hashes("org.bar"), "org.foo"); - - jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*"); - checkHashes(hashes("m3"), "org.foo", "org.bar", "m1"); + ht.checkHashes("java.xml.bind", "java.xml.ws", "m2"); } - private void checkHashes(ModuleHashes hashes, String... hashModules) { + @Test + public static void testImageJmods() throws IOException { + Path mpath = Paths.get(System.getProperty("java.home"), "jmods"); + if (!Files.exists(mpath)) { + return; + } + + Path dest = Paths.get("test5"); + HashesTest ht = new HashesTest(dest); + ht.makeModule("m1", "jdk.compiler", "jdk.attach"); + ht.makeModule("m2", "m1"); + ht.makeModule("m3", "java.compiler"); + + ht.makeJmod("m1"); + ht.makeJmod("m2"); + + runJmod(List.of("hash", + "--module-path", + mpath.toString() + File.pathSeparator + ht.lib.toString(), + "--hash-modules", ".*")); + + validateImageJmodsTest(ht, mpath); + } + + @Test + public static void testImageJmods1() throws IOException { + Path mpath = Paths.get(System.getProperty("java.home"), "jmods"); + if (!Files.exists(mpath)) { + return; + } + + Path dest = Paths.get("test6"); + HashesTest ht = new HashesTest(dest); + ht.makeModule("m1", "jdk.compiler", "jdk.attach"); + ht.makeModule("m2", "m1"); + ht.makeModule("m3", "java.compiler"); + + ht.makeJar("m2"); + ht.makeJar("m1", + "--module-path", + mpath.toString() + File.pathSeparator + ht.lib.toString(), + "--hash-modules", ".*"); + validateImageJmodsTest(ht, mpath); + } + + private static void validateImageJmodsTest(HashesTest ht, Path mpath) + throws IOException + { + // hash is recorded in m1 and not any other packaged modules on module path + ht.checkHashes("m1", "m2"); + assertTrue(ht.hashes("m2") == null); + + // should not override any JDK packaged modules + ModuleFinder finder = new ModulePath(Runtime.version(), + true, + mpath); + assertTrue(ht.hashes(finder,"jdk.compiler") == null); + assertTrue(ht.hashes(finder,"jdk.attach") == null); + } + + private void checkHashes(String mn, String... hashModules) throws IOException { + ModuleHashes hashes = hashes(mn); assertTrue(hashes.names().equals(Set.of(hashModules))); } - private ModuleHashes hashes(String name) throws Exception { + private ModuleHashes hashes(String name) { ModuleFinder finder = new ModulePath(Runtime.version(), true, - jmods.resolve(name + ".jmod")); + lib); + return hashes(finder, name); + } + + private ModuleHashes hashes(ModuleFinder finder, String name) { ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new); - ModuleReader reader = mref.open(); - try (InputStream in = reader.open("module-info.class").get()) { - ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes(); - System.out.format("hashes in module %s %s%n", name, + try { + ModuleReader reader = mref.open(); + try (InputStream in = reader.open("module-info.class").get()) { + ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes(); + System.out.format("hashes in module %s %s%n", name, (hashes != null) ? "present" : "absent"); - if (hashes != null) { - hashes.names().stream() - .sorted() - .forEach(n -> System.out.format(" %s %s%n", n, hashes.hashFor(n))); + if (hashes != null) { + hashes.names().stream().sorted().forEach(n -> + System.out.format(" %s %s%n", n, toHex(hashes.hashFor(n))) + ); + } + return hashes; + } finally { + reader.close(); } - return hashes; - } finally { - reader.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); } } + private String toHex(byte[] ba) { + StringBuilder sb = new StringBuilder(ba.length); + for (byte b: ba) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } + private void deleteDirectory(Path dir) throws IOException { Files.walkFileTree(dir, new SimpleFileVisitor() { @Override @@ -176,31 +381,94 @@ }); } + + private void makeModule(String mn, String... deps) throws IOException { + makeModule(mn, null, deps); + } + + private void makeModule(String mn, ModuleDescriptor.Requires.Modifier mod, String... deps) + throws IOException + { + if (mod != null && mod != TRANSITIVE && mod != STATIC) { + throw new IllegalArgumentException(mod.toString()); + } + + StringBuilder sb = new StringBuilder(); + sb.append("module " + mn + " {").append("\n"); + Arrays.stream(deps).forEach(req -> { + sb.append(" requires "); + if (mod != null) { + sb.append(mod.toString().toLowerCase()).append(" "); + } + sb.append(req + ";\n"); + }); + sb.append("}\n"); + builder.writeJavaFiles(mn, sb.toString()); + + compileModule(mn, srcDir); + } + private void compileModule(String moduleName, Path src) throws IOException { Path msrc = src.resolve(moduleName); assertTrue(CompilerUtils.compile(msrc, mods, "--module-source-path", src.toString())); } - private void jmod(String moduleName, String... options) throws IOException { + private void jmodHashModules(String moduleName, String hashModulesPattern) { + makeJmod(moduleName, "--module-path", lib.toString(), + "--hash-modules", hashModulesPattern); + } + + private void makeJmod(String moduleName, String... options) { Path mclasses = mods.resolve(moduleName); - Path outfile = jmods.resolve(moduleName + ".jmod"); + Path outfile = lib.resolve(moduleName + ".jmod"); List args = new ArrayList<>(); args.add("create"); Collections.addAll(args, options); Collections.addAll(args, "--class-path", mclasses.toString(), outfile.toString()); - if (Files.exists(outfile)) - Files.delete(outfile); - + if (Files.exists(outfile)) { + try { + Files.delete(outfile); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } runJmod(args); } - private void runJmod(List args) { + private static void runJmod(List args) { int rc = JMOD_TOOL.run(System.out, System.out, args.toArray(new String[args.size()])); - System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" "))); + System.out.println("jmod " + args.stream().collect(Collectors.joining(" "))); if (rc != 0) { - throw new AssertionError("Jmod failed: rc = " + rc); + throw new AssertionError("jmod failed: rc = " + rc); + } + } + + private void makeJar(String moduleName, String... options) { + Path mclasses = mods.resolve(moduleName); + Path outfile = lib.resolve(moduleName + ".jar"); + List args = new ArrayList<>(); + Stream.concat(Stream.of("--create", + "--file=" + outfile.toString()), + Arrays.stream(options)) + .forEach(args::add); + args.add("-C"); + args.add(mclasses.toString()); + args.add("."); + + if (Files.exists(outfile)) { + try { + Files.delete(outfile); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + int rc = JAR_TOOL.run(System.out, System.out, args.toArray(new String[args.size()])); + System.out.println("jar " + args.stream().collect(Collectors.joining(" "))); + if (rc != 0) { + throw new AssertionError("jar failed: rc = " + rc); } } } diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/m1/module-info.java --- a/jdk/test/tools/jmod/hashes/src/m1/module-info.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m1 { - requires m2; - requires m3; -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/m1/org/m1/Main.java --- a/jdk/test/tools/jmod/hashes/src/m1/org/m1/Main.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.m1; - -import org.m2.Util; -import org.m3.Name; - -public class Main { - public static void main(String[] args) { - System.out.println(Util.timeOfDay()); - System.out.println(Name.name()); - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/m2/module-info.java --- a/jdk/test/tools/jmod/hashes/src/m2/module-info.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m2 { - exports org.m2; -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/m2/org/m2/Util.java --- a/jdk/test/tools/jmod/hashes/src/m2/org/m2/Util.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.m2; - -public class Util { - private Util() { } - - public static String timeOfDay() { - return "Time for lunch"; - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/m3/module-info.java --- a/jdk/test/tools/jmod/hashes/src/m3/module-info.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m3 { - exports org.m3; -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/m3/org/m3/Name.java --- a/jdk/test/tools/jmod/hashes/src/m3/org/m3/Name.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.m3; - -public class Name { - private Name() { } - - public static String name() { - return "m3"; - } -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/org.bar/module-info.java --- a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module org.bar { - requires transitive m1; -} diff -r 047a57b0839a -r 1c9922f121ff jdk/test/tools/jmod/hashes/src/org.foo/module-info.java --- a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java Tue Jan 17 07:41:04 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module org.foo { - requires transitive org.bar; -} diff -r 047a57b0839a -r 1c9922f121ff make/Bundles.gmk --- a/make/Bundles.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/Bundles.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -77,9 +77,8 @@ $$(call MakeDir, $$(@D)) ifneq ($$($1_SPECIAL_INCLUDES), ) $$(foreach i, $$($1_SPECIAL_INCLUDES), \ - $$(foreach d, $$d, \ - ($(CD) $$d && $(FIND) $$i \ - >> $(SUPPORT_OUTPUTDIR)/bundles/_$1_files ) ; )) + $$(foreach d, $$($1_BASE_DIRS), \ + ($(CD) $$d && $(FIND) $$i >> $$($1_$$d_LIST_FILE)) ; )) endif ifeq ($$($1_SUBDIR)-$$($1_TYPE)-$$($1_UNZIP_DEBUGINFO), .-zip-false) # If no subdir is specified, zip can be done directly from BASE_DIRS. @@ -152,6 +151,9 @@ JRE_IMAGE_HOMEDIR := $(JRE_IMAGE_DIR) JDK_BUNDLE_SUBDIR := jdk-$(VERSION_NUMBER) JRE_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER) + JRE_COMPACT1_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)-compact1 + JRE_COMPACT2_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)-compact2 + JRE_COMPACT3_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)-compact3 ifneq ($(DEBUG_LEVEL), release) JDK_BUNDLE_SUBDIR := $(JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL) JRE_BUNDLE_SUBDIR := $(JRE_BUNDLE_SUBDIR)/$(DEBUG_LEVEL) @@ -281,6 +283,35 @@ ################################################################################ +ifneq ($(filter profiles-bundles, $(MAKECMDGOALS)), ) + ifeq ($(OPENJDK_TARGET_OS), macosx) + $(error Creating compact profiles bundles on macosx is unsupported) + endif + + define GenerateCompactProfilesBundles + ALL_JRE_COMPACT$1_FILES := $$(call CacheFind, $$(JRE_COMPACT$1_IMAGE_DIR)) + + JRE_COMPACT$1_BUNDLE_FILES := $$(filter-out \ + $$(SYMBOLS_EXCLUDE_PATTERN), \ + $$(ALL_JRE_COMPACT$1_FILES)) + + $$(eval $$(call SetupBundleFile, BUILD_JRE_COMPACT$1_BUNDLE, \ + BUNDLE_NAME := $$(JRE_COMPACT$1_BUNDLE_NAME), \ + FILES := $$(JRE_COMPACT$1_BUNDLE_FILES), \ + BASE_DIRS := $$(JRE_COMPACT$1_IMAGE_DIR), \ + SUBDIR := $$(JRE_COMPACT$1_BUNDLE_SUBDIR), \ + )) + + PROFILES_TARGETS += $$(BUILD_JRE_COMPACT$1_BUNDLE) + endef + + $(eval $(call GenerateCompactProfilesBundles,1)) + $(eval $(call GenerateCompactProfilesBundles,2)) + $(eval $(call GenerateCompactProfilesBundles,3)) +endif + +################################################################################ + ifneq ($(filter test-bundles, $(MAKECMDGOALS)), ) TEST_BUNDLE_FILES := $(call CacheFind, $(TEST_IMAGE_DIR)) @@ -316,7 +347,8 @@ ################################################################################ product-bundles: $(PRODUCT_TARGETS) +profiles-bundles: $(PROFILES_TARGETS) test-bundles: $(TEST_TARGETS) docs-bundles: $(DOCS_TARGETS) -.PHONY: all default product-bundles test-bundles docs-bundles +.PHONY: all default product-bundles profiles-bundles test-bundles docs-bundles diff -r 047a57b0839a -r 1c9922f121ff make/CompileJavaModules.gmk --- a/make/CompileJavaModules.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/CompileJavaModules.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -383,6 +383,10 @@ ################################################################################ +jdk.jartool_ADD_JAVAC_FLAGS := -XDstringConcat=inline + +################################################################################ + jdk.rmic_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS jdk.rmic_CLEAN := .properties diff -r 047a57b0839a -r 1c9922f121ff make/Images.gmk --- a/make/Images.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/Images.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -147,10 +147,6 @@ --output $(JRE_IMAGE_DIR) $(TOUCH) $@ -JRE_COMPACT1_IMAGE_DIR := $(JRE_IMAGE_DIR)-compact1 -JRE_COMPACT2_IMAGE_DIR := $(JRE_IMAGE_DIR)-compact2 -JRE_COMPACT3_IMAGE_DIR := $(JRE_IMAGE_DIR)-compact3 - $(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \ $(call DependOnVariable, JRE_COMPACT1_MODULES_LIST) $(BASE_RELEASE_FILE) diff -r 047a57b0839a -r 1c9922f121ff make/Javadoc.gmk --- a/make/Javadoc.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/Javadoc.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -1,4 +1,4 @@ -# Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ DRAFT_WINDOW_TITLE_MARKER := $(SPACE)[build $(VERSION_BUILD)] endif EARLYACCESS_TOP := \ -

    Please note that the specifications \ @@ -235,10 +235,6 @@ $1_OPTIONS += --add-modules $$(call CommaList, $$($1_MODULES)) - ifneq ($$(LOG_LEVEL), trace) - $1_OPTIONS += -quiet - endif - ifneq ($$($1_DISABLED_DOCLINT), ) # Create a string like ",-syntax,-html" $1_DOCLINT_EXCEPTIONS := ,$$(call CommaList, $$(addprefix -, $$($1_DISABLED_DOCLINT))) @@ -292,6 +288,13 @@ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \ $$(SUPPORT_OUTPUTDIR)/docs/$1.vardeps) + # Do not store debug level options in VARDEPS. + ifneq ($$(LOG_LEVEL), trace) + $1_OPTIONS += -quiet + else + $1_OPTIONS += -verbose + endif + $1_PACKAGE_DEPS := $$(call CacheFind, $$(wildcard $$(foreach p, \ $$(subst .,/,$$(strip $$($1_PACKAGES))), \ $$(addsuffix /$$p, $$(wildcard $$(JAVADOC_SOURCE_DIRS)))))) diff -r 047a57b0839a -r 1c9922f121ff make/Main.gmk --- a/make/Main.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/Main.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -342,7 +342,7 @@ symbols-image: +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Images.gmk symbols) -profiles: +profiles-image: +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Images.gmk profiles) mac-bundles-jdk: @@ -356,7 +356,7 @@ ALL_TARGETS += store-source-revision create-source-revision-tracker bootcycle-images zip-security \ zip-source jrtfs-jar jdk-image jre-image \ - symbols-image profiles mac-bundles-jdk \ + symbols-image profiles-image mac-bundles-jdk \ release-file exploded-image-optimize ################################################################################ @@ -510,13 +510,16 @@ product-bundles: +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk product-bundles) +profiles-bundles: + +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk profiles-bundles) + test-bundles: +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk test-bundles) docs-bundles: +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk docs-bundles) -ALL_TARGETS += product-bundles test-bundles docs-bundles +ALL_TARGETS += product-bundles profiles-bundles test-bundles docs-bundles ################################################################################ # Install targets @@ -734,7 +737,7 @@ jre-image: jmods release-file symbols-image: $(LIBS_TARGETS) $(LAUNCHER_TARGETS) - profiles: jmods release-file + profiles-image: jmods release-file mac-bundles-jdk: jdk-image jre-image @@ -793,6 +796,8 @@ product-bundles: product-images + profiles-bundles: profiles-images + test-bundles: test-image docs-bundles: docs-image @@ -878,6 +883,9 @@ # an image until this can be cleaned up properly. product-images: zip-security +# Declare these for backwards compatiblity and convenience. +profiles profiles-images: profiles-image + # The module summary cannot be run when: # * Cross compiling and building a partial BUILDJDK for the build host # * An external buildjdk has been supplied since it may not match the @@ -909,7 +917,9 @@ copy java rmic libs launchers jmods \ jdk.jdwp.agent-gensrc $(ALL_MODULES) demos samples \ exploded-image-base exploded-image \ - create-buildjdk mac-bundles product-images docs-image test-image all-images \ + create-buildjdk mac-bundles product-images \ + profiles profiles-images \ + docs-image test-image all-images \ all-bundles ################################################################################ diff -r 047a57b0839a -r 1c9922f121ff make/common/MakeBase.gmk --- a/make/common/MakeBase.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/common/MakeBase.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -435,7 +435,7 @@ Too many named arguments to macro, please update MAX_PARAMS in MakeBase.gmk)) # Iterate over 2 3 4... and evaluate the named parameters with $1_ as prefix $(foreach i,$(PARAM_SEQUENCE), $(if $(strip $($i)),\ - $(strip $1)_$(strip $(call DoubleDollar, $($i))))$(NEWLINE)) + $(strip $1)_$(strip $(call EscapeHash, $(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), \ diff -r 047a57b0839a -r 1c9922f121ff make/common/NativeCompilation.gmk --- a/make/common/NativeCompilation.gmk Tue Jan 17 07:41:04 2017 +0100 +++ b/make/common/NativeCompilation.gmk Wed Jul 05 22:42:01 2017 +0200 @@ -288,8 +288,7 @@ $$($1_$(notdir $2)_OPTIMIZATION)), ) $1_$2_VARDEPS := $$($1_$(notdir $2)_CFLAGS) $$($1_$(notdir $2)_CXXFLAGS) \ $$($1_$(notdir $2)_OPT_CFLAGS) $$($1_$(notdir $2)_OPT_CXXFLAGS) - $1_$2_VARDEPS_FILE := $$(call DependOnVariable, $1_$2_VARDEPS, \ - $$(patsubst %$(OBJ_SUFFIX),%.vardeps,$$($1_$2_OBJ))) + $1_$2_VARDEPS_FILE := $$(call DependOnVariable, $1_$2_VARDEPS, $$($1_$2_OBJ).vardeps) endif $$($1_$2_OBJ) : $2 $$($1_COMPILE_VARDEPS_FILE) $$($1_$2_VARDEPS_FILE) | $$($1_BUILD_INFO) diff -r 047a57b0839a -r 1c9922f121ff nashorn/.hgtags --- a/nashorn/.hgtags Tue Jan 17 07:41:04 2017 +0100 +++ b/nashorn/.hgtags Wed Jul 05 22:42:01 2017 +0200 @@ -385,3 +385,4 @@ c281306d33d83c92e0d870ace385d5f99678d7e7 jdk-9+149 ace1d994bca775d6545a4c874ae73d1dfc9ec18b jdk-9+150 2a0437036a64853334e538044eb68d2df70075fa jdk-9+151 +ddc52e72757086a75a54371e8e7f56a3f89f1e55 jdk-9+152 diff -r 047a57b0839a -r 1c9922f121ff nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Tue Jan 17 07:41:04 2017 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Wed Jul 05 22:42:01 2017 +0200 @@ -1032,7 +1032,7 @@ } final Object key = property.getKey(); - property = iter.next(); + property = iter.hasNext() ? iter.next() : null; skipNotEnumerable(); return key; diff -r 047a57b0839a -r 1c9922f121ff nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Jan 17 07:41:04 2017 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Jul 05 22:42:01 2017 +0200 @@ -28,6 +28,8 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -100,7 +102,7 @@ * reparsed from source, or a soft reference to a {@code FunctionNode} for other functions (it is safe * to be cleared as they can be reparsed). */ - private volatile Object cachedAst; + private volatile transient Object cachedAst; /** Token of this function within the source. */ private final long token; @@ -289,6 +291,9 @@ if (this.source == null && this.installer == null) { this.source = src; this.installer = inst; + for (final RecompilableScriptFunctionData nested : nestedFunctions.values()) { + nested.initTransients(src, inst); + } } else if (this.source != src || !this.installer.isCompatibleWith(inst)) { // Existing values must be same as those passed as parameters throw new IllegalArgumentException(); @@ -424,7 +429,7 @@ } else if (lCachedAst instanceof SerializedAst) { final SerializedAst serializedAst = (SerializedAst)lCachedAst; // Even so, are we also softly caching the AST? - final FunctionNode cachedFn = serializedAst.cachedAst.get(); + final FunctionNode cachedFn = serializedAst.cachedAst == null ? null : serializedAst.cachedAst.get(); if (cachedFn != null) { // Yes we are - this is fast return cloneSymbols(cachedFn); @@ -492,9 +497,11 @@ * we're using this tuple instead to also keep a deserialized AST around in memory to cut down on * deserialization costs. */ - private static class SerializedAst { + private static class SerializedAst implements Serializable { private final byte[] serializedAst; - private volatile Reference cachedAst; + private volatile transient Reference cachedAst; + + private static final long serialVersionUID = 1L; SerializedAst(final FunctionNode fn, final Reference cachedAst) { this.serializedAst = AstSerializer.serialize(fn); @@ -1038,8 +1045,20 @@ return true; } + private void writeObject(final ObjectOutputStream out) throws IOException { + final Object localCachedAst = cachedAst; + out.defaultWriteObject(); + // We need to persist SerializedAst for split functions as they can't reparse the source code. + if (localCachedAst instanceof SerializedAst) { + out.writeObject(localCachedAst); + } else { + out.writeObject(null); + } + } + private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + cachedAst = in.readObject(); createLogger(); } diff -r 047a57b0839a -r 1c9922f121ff nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/fx/base.js --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/fx/base.js Tue Jan 17 07:41:04 2017 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/fx/base.js Wed Jul 05 22:42:01 2017 +0200 @@ -108,7 +108,7 @@ } }); - Files.walkFileTree(rootDirectories[0], new JRTFSWalker()); + Files.walkFileTree(rootDirectories.toArray()[0], new JRTFSWalker()); })(); LOAD_FX_CLASSES(this, "javafx.base"); diff -r 047a57b0839a -r 1c9922f121ff nashorn/test/src/jdk/nashorn/internal/runtime/test/CodeStoreAndPathTest.java --- a/nashorn/test/src/jdk/nashorn/internal/runtime/test/CodeStoreAndPathTest.java Tue Jan 17 07:41:04 2017 +0100 +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/test/CodeStoreAndPathTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -47,7 +47,7 @@ @SuppressWarnings("javadoc") public class CodeStoreAndPathTest { - final String code1 = "var code1; var x = 'Hello Script'; var x1 = 'Hello Script'; " + final static String code1 = "var code1; var x = 'Hello Script'; var x1 = 'Hello Script'; " + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; " + "var x4 = 'Hello Script'; var x5 = 'Hello Script';" + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; " @@ -69,7 +69,7 @@ + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + "var x10 = 'Hello Script';}"; - final String code2 = "var code2; var x = 'Hello Script'; var x1 = 'Hello Script'; " + final static String code2 = "var code2; var x = 'Hello Script'; var x1 = 'Hello Script'; " + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; " + "var x4 = 'Hello Script'; var x5 = 'Hello Script';" + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; " @@ -92,9 +92,306 @@ + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + "var x10 = 'Hello Script';}"; // Script size < Default minimum size for storing a compiled script class - final String code3 = "var code3; var x = 'Hello Script'; var x1 = 'Hello Script'; "; - final String codeCache = "build/nashorn_code_cache"; - final String oldUserDir = System.getProperty("user.dir"); + final static String code3 = "var code3; var x = 'Hello Script'; var x1 = 'Hello Script'; "; + final static String nestedFunctions = "\n" + + "(function outer() { \n" + + " var map = null; \n" + + " (function inner() { \n" + + " var object; \n" + + " if (map === null) { \n" + + " map = (function() { \n" + + " var HashMap = Java.type('java.util.HashMap'); \n" + + " map = new HashMap(); \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " return map; \n" + + " }()); \n" + + " } \n" + + " object = {}; \n" + + " return object; \n" + + " })(); \n" + + "}()); "; + final static String longNestedFunctions = "\n" + + "(function outer() { \n" + + " var map = null; \n" + + " (function inner() { \n" + + " var object; \n" + + " var HashMap = Java.type('java.util.HashMap'); \n" + + " map = new HashMap(); \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address';\n" + + " map.name = 'name'; \n" + + " map.id = 1234;\n" + + " map.basePath = 'basePath'; \n" + + " map.extensionPath = 'extension';\n" + + " map.address = 'address'; \n" + + " object = {}; \n" + + " return object; \n" + + " })(); \n" + + "}()); "; + final static String codeCache = "build/nashorn_code_cache"; + final static String oldUserDir = System.getProperty("user.dir"); private static final String[] ENGINE_OPTIONS_OPT = new String[]{"--persistent-code-cache", "--optimistic-types=true"}; private static final String[] ENGINE_OPTIONS_NOOPT = new String[]{"--persistent-code-cache", "--optimistic-types=false"}; @@ -166,6 +463,28 @@ checkCompiledScripts(stream, 4); } + @Test + public void testNestedFunctionStore() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(nestedFunctions); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(nestedFunctions); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(nestedFunctions); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(nestedFunctions); + } + + @Test + public void testSplitFunctionStore() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + System.setProperty("nashorn.compiler.splitter.threshold", "500"); + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(longNestedFunctions); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(longNestedFunctions); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(longNestedFunctions); + factory.getScriptEngine(ENGINE_OPTIONS_OPT).eval(longNestedFunctions); + System.getProperties().remove("nashorn.compiler.splitter.threshold"); + } + private static Path getCodeCachePath(final boolean optimistic) { final String codeCache = System.getProperty("nashorn.persistent.code.cache"); final Path codeCachePath = FileSystems.getDefault().getPath(codeCache).toAbsolutePath(); diff -r 047a57b0839a -r 1c9922f121ff nashorn/test/src/jdk/nashorn/internal/runtime/test/PropertyMapTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/test/PropertyMapTest.java Wed Jul 05 22:42:01 2017 +0200 @@ -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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime.test; + +import java.util.Iterator; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptObject; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * Tests for PropertyMap functionality + * + * @test + * @modules jdk.scripting.nashorn/jdk.nashorn.internal.runtime + * @run testng jdk.nashorn.internal.runtime.test.PropertyMapTest + */ +@SuppressWarnings("javadoc") +public class PropertyMapTest { + + @Test + public void propertyMapIteratorTest() { + final ScriptObject scriptObject = new ScriptObject(PropertyMap.newMap()) {}; + Assert.assertFalse(scriptObject.getMap().iterator().hasNext()); + + scriptObject.set("a", "a", 0); + scriptObject.set("b", 3, 0); + // 3 is a valid array key not stored in property map + scriptObject.set(3, 1, 0); + scriptObject.set(6.5, 1.3, 0); + final Iterator iterator = scriptObject.getMap().iterator(); + + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), "a"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), "b"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), "6.5"); + Assert.assertFalse(iterator.hasNext()); + } + +} diff -r 047a57b0839a -r 1c9922f121ff test/failure_handler/src/share/conf/mac.properties --- a/test/failure_handler/src/share/conf/mac.properties Tue Jan 17 07:41:04 2017 +0100 +++ b/test/failure_handler/src/share/conf/mac.properties Wed Jul 05 22:42:01 2017 +0200 @@ -64,7 +64,7 @@ native.core.app=bash native.core.delimiter=\0 native.core.args=-c\0gcore -o ./core.%p %p || \ - (DevToolsSecurity --status | grep -q enabled && lldb -o 'attach %p' -o 'process save-core core.%p' -o 'detach' -o 'quit') + (DevToolsSecurity --status | grep -q enabled && lldb --batch -o 'attach %p' -o 'process save-core core.%p' -o 'detach' -o 'quit') native.core.params.timeout=3600000 ################################################################################ # environment info to gather diff -r 047a57b0839a -r 1c9922f121ff test/lib/jdk/test/lib/SecurityTools.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/lib/jdk/test/lib/SecurityTools.java Wed Jul 05 22:42:01 2017 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.lib; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class SecurityTools { + + public static final String NO_ALIAS = null; + + // keytool + + public static OutputAnalyzer keytool(List options) + throws Throwable { + + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("keytool") + .addVMArg("-Duser.language=en") + .addVMArg("-Duser.country=US"); + for (String option : options) { + if (option.startsWith("-J")) { + launcher.addVMArg(option.substring(2)); + } else { + launcher.addToolArg(option); + } + } + return ProcessTools.executeCommand(launcher.getCommand()); + } + + public static OutputAnalyzer keytool(String options) throws Throwable { + return keytool(options.split("\\s+")); + } + + public static OutputAnalyzer keytool(String... options) throws Throwable { + return keytool(List.of(options)); + } + + // jarsigner + + public static OutputAnalyzer jarsigner(String jar, String alias, + List options) throws Throwable { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner") + .addVMArg("-Duser.language=en") + .addVMArg("-Duser.country=US"); + for (String option : options) { + if (option.startsWith("-J")) { + launcher.addVMArg(option.substring(2)); + } else { + launcher.addToolArg(option); + } + } + launcher.addToolArg(jar); + if (alias != null) { + launcher.addToolArg(alias); + } + return ProcessTools.executeCommand(launcher.getCommand()); + } + + public static OutputAnalyzer jarsigner(String jar, String alias, + String options) throws Throwable { + + return jarsigner(jar, alias, options.split("\\s+")); + } + + public static OutputAnalyzer jarsigner(String jar, String alias, + String... options) throws Throwable { + + return jarsigner(jar, alias, List.of(options)); + } + + public static OutputAnalyzer sign(String jar, String alias, String... options) + throws Throwable { + + return jarsigner(jar, alias, + mergeOptions("-J-Djava.security.egd=file:/dev/./urandom", options)); + } + + public static OutputAnalyzer verify(String jar, String... options) + throws Throwable { + + return jarsigner(jar, NO_ALIAS, mergeOptions("-verify", options)); + } + + // helper methods + + private static List mergeOptions( + String firstOption, String... secondPart) { + + return mergeOptions(List.of(firstOption), secondPart); + } + + private static List mergeOptions( + List firstPart, String... secondPart) { + + List options = new ArrayList<>(firstPart); + Collections.addAll(options, secondPart); + return options; + } +} +