# HG changeset patch # User lana # Date 1484271367 0 # Node ID 69b209a7a0a41f8a884dc9dc5e27744e9fe7d9c5 # Parent ed4f16888e1231aa9998080da18d0e7415abbd27# Parent 22875dc4eec58bf3a7656742ce949f81b8877039 Merge diff -r ed4f16888e12 -r 69b209a7a0a4 jdk/make/data/fontconfig/solaris.fontconfig.properties --- a/jdk/make/data/fontconfig/solaris.fontconfig.properties Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/make/data/fontconfig/solaris.fontconfig.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/make/lib/Awt2dLibraries.gmk --- a/jdk/make/lib/Awt2dLibraries.gmk Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/make/lib/Awt2dLibraries.gmk Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/lang/Class.java --- a/jdk/src/java.base/share/classes/java/lang/Class.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/Class.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 @@ * * @@ -2570,7 +2570,7 @@ * * diff -r ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/lang/ClassLoader.java --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/net/URLConnection.java --- a/jdk/src/java.base/share/classes/java/net/URLConnection.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/net/URLConnection.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/util/Collections.java --- a/jdk/src/java.base/share/classes/java/util/Collections.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/Collections.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/util/ImmutableCollections.java --- a/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/util/KeyValueHolder.java --- a/jdk/src/java.base/share/classes/java/util/KeyValueHolder.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/KeyValueHolder.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/util/List.java --- a/jdk/src/java.base/share/classes/java/util/List.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/List.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/util/Map.java --- a/jdk/src/java.base/share/classes/java/util/Map.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/Map.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.base/share/classes/java/util/Set.java --- a/jdk/src/java.base/share/classes/java/util/Set.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/Set.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/java/beans/AppletInitializer.java --- a/jdk/src/java.desktop/share/classes/java/beans/AppletInitializer.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/java/beans/AppletInitializer.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/java/beans/Beans.java --- a/jdk/src/java.desktop/share/classes/java/beans/Beans.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/java/beans/Beans.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/javax/swing/PopupFactory.java --- a/jdk/src/java.desktop/share/classes/javax/swing/PopupFactory.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/PopupFactory.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java --- a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java --- a/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletEvent.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletEvent.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletEvent.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletEventMulticaster.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletEventMulticaster.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletEventMulticaster.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletIOException.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletIOException.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletIOException.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletIllegalArgumentException.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletIllegalArgumentException.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletIllegalArgumentException.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletImageRef.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletImageRef.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletImageRef.java Fri Jan 13 01:36:07 2017 +0000 @@ -31,6 +31,7 @@ import sun.awt.image.URLImageSource; import java.net.URL; +@Deprecated(since = "9") class AppletImageRef { private SoftReference soft = null; diff -r ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletListener.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletListener.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletListener.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletObjectInputStream.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletObjectInputStream.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletObjectInputStream.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletProps.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletProps.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletProps.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewer.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletViewerFactory.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerFactory.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerFactory.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/AppletViewerPanel.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerPanel.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletViewerPanel.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/applet/Main.java --- a/jdk/src/java.desktop/share/classes/sun/applet/Main.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/applet/Main.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java --- a/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/share/native/libmlib_image/safe_alloc.h --- a/jdk/src/java.desktop/share/native/libmlib_image/safe_alloc.h Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/share/native/libmlib_image/safe_alloc.h Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java --- a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java Fri Jan 13 01:36:07 2017 +0000 @@ -169,9 +169,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 +201,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 +280,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 +323,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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Fri Jan 13 01:36:07 2017 +0000 @@ -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; @@ -47,6 +48,7 @@ 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; @@ -74,58 +76,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 +109,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 +117,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 +147,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 +155,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 +250,6 @@ } } } - if (cflag) { Manifest manifest = null; if (!Mflag) { @@ -347,72 +272,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 +333,7 @@ Files.deleteIfExists(packFile.toPath()); } } - validateAndClose(tmpfile); - } else if (uflag) { File inputFile = null, tmpFile = null; if (fname != null) { @@ -432,39 +343,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 +434,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 { + ok = Validator.validate(this, tmpfile); + 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 +467,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 +494,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 +679,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 +739,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 +768,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 +820,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 +877,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 +890,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 +903,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 +922,6 @@ return false; } } - // Update the manifest. Manifest old = new Manifest(zis); if (newManifest != null) { @@ -1137,7 +931,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 +954,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 +963,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 +982,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 +1015,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 +1146,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 +1230,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 +1244,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 +1605,7 @@ */ void usageError(String s) { err.println(s); - Info.USAGE_TRYHELP.print(err); + err.println(getMsg("main.usage.summary.try")); } /** @@ -1934,16 +1714,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 +1721,6 @@ CharSequence suffix ) { if (c.isEmpty()) return ""; - return c.stream().map(e -> e.toString()) .collect(joining(", ", prefix, suffix)); } @@ -2045,136 +1814,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 +1902,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 +1917,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) { diff -r ed4f16888e12 -r 69b209a7a0a4 jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java Fri Jan 13 01:36:07 2017 +0000 @@ -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, File f) throws IOException { + return new Validator(main, new JarFile(f)).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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_es.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_fr.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_it.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ko.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_pt_BR.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_sv.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_TW.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Fri Jan 13 01:36:07 2017 +0000 @@ -1088,34 +1088,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 +1151,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 +1162,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 +1330,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 +1370,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 +1391,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 +1458,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 +1537,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 +1571,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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java --- a/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java --- a/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java --- a/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java --- a/jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/awt/print/PrinterJob/BannerTest.java --- a/jdk/test/java/awt/print/PrinterJob/BannerTest.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/awt/print/PrinterJob/BannerTest.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java --- a/jdk/test/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java --- a/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/registry/altSecurityManager/TestSecurityManager.java --- a/jdk/test/java/rmi/registry/altSecurityManager/TestSecurityManager.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/registry/altSecurityManager/TestSecurityManager.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java --- a/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/registry/classPathCodebase/ClassPathCodebase.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/registry/classPathCodebase/security.policy --- a/jdk/test/java/rmi/registry/classPathCodebase/security.policy Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/registry/classPathCodebase/security.policy Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/registry/reexport/Reexport.java --- a/jdk/test/java/rmi/registry/reexport/Reexport.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/registry/reexport/Reexport.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/testlibrary/JavaVM.java --- a/jdk/test/java/rmi/testlibrary/JavaVM.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/testlibrary/JavaVM.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/testlibrary/REGISTRY.java --- a/jdk/test/java/rmi/testlibrary/REGISTRY.java Thu Jan 12 23:41:17 2017 +0000 +++ /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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/testlibrary/RMID.java --- a/jdk/test/java/rmi/testlibrary/RMID.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/testlibrary/RMID.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/testlibrary/RegistryRunner.java --- a/jdk/test/java/rmi/testlibrary/RegistryRunner.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/testlibrary/RegistryRunner.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/testlibrary/TestParams.java --- a/jdk/test/java/rmi/testlibrary/TestParams.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/testlibrary/TestParams.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java --- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/TEST.properties --- a/jdk/test/java/time/TEST.properties Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/TEST.properties Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java --- a/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/test/java/time/format/TestNarrowMonthNamesAndDayNames.java --- a/jdk/test/java/time/test/java/time/format/TestNarrowMonthNamesAndDayNames.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestNarrowMonthNamesAndDayNames.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java --- a/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/test/java/time/format/TestTextParser.java --- a/jdk/test/java/time/test/java/time/format/TestTextParser.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestTextParser.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/time/test/java/time/format/TestTextPrinter.java --- a/jdk/test/java/time/test/java/time/format/TestTextPrinter.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/time/test/java/time/format/TestTextPrinter.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/util/Collection/SetFactories.java --- a/jdk/test/java/util/Collection/SetFactories.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/util/Collection/SetFactories.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/java/util/Map/MapFactories.java --- a/jdk/test/java/util/Map/MapFactories.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/java/util/Map/MapFactories.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java --- a/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/lib/security/SecurityTools.java --- a/jdk/test/lib/security/SecurityTools.java Thu Jan 12 23:41:17 2017 +0000 +++ /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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java --- a/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/sun/security/tools/keytool/PrintSSL.java --- a/jdk/test/sun/security/tools/keytool/PrintSSL.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/sun/security/tools/keytool/PrintSSL.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/sun/security/tools/keytool/ReadJar.java --- a/jdk/test/sun/security/tools/keytool/ReadJar.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/sun/security/tools/keytool/ReadJar.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/tools/jar/mmrjar/ConcealedPackage.java --- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java Thu Jan 12 23:41:17 2017 +0000 +++ /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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/tools/jar/modularJar/Basic.java --- a/jdk/test/tools/jar/modularJar/Basic.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/tools/jar/modularJar/Basic.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 jdk/test/tools/jar/multiRelease/Basic1.java --- a/jdk/test/tools/jar/multiRelease/Basic1.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/tools/jar/multiRelease/Basic1.java Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -0,0 +1,1 @@ +8 \ No newline at end of file diff -r ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -0,0 +1,1 @@ +Main-Class: testpackage.Main diff -r ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -0,0 +1,1 @@ +10 diff -r ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -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 ed4f16888e12 -r 69b209a7a0a4 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 Fri Jan 13 01:36:07 2017 +0000 @@ -0,0 +1,1 @@ +9 diff -r ed4f16888e12 -r 69b209a7a0a4 jdk/test/tools/jmod/JmodTest.java --- a/jdk/test/tools/jmod/JmodTest.java Thu Jan 12 23:41:17 2017 +0000 +++ b/jdk/test/tools/jmod/JmodTest.java Fri Jan 13 01:36:07 2017 +0000 @@ -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);