From 8aa80a9245798ef7895c06a11705c651b79aa1c2 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 6 Nov 2015 14:32:34 +0100 Subject: [PATCH 001/151] 8141526: Allow to collect stdout/stderr from the FinalizationRunner even before the process returns Reviewed-by: dsamersoff --- jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java | 4 ++++ .../lib/testlibrary/jdk/testlibrary/JDKToolFinder.java | 5 +++++ .../lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java | 3 +++ .../lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java | 5 +++++ .../lib/testlibrary/jdk/testlibrary/OutputBuffer.java | 5 +++++ jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java | 5 +++++ .../lib/testlibrary/jdk/testlibrary/ProcessTools.java | 8 ++++++-- .../lib/testlibrary/jdk/testlibrary/StreamPumper.java | 5 +++++ jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java | 4 ++++ 9 files changed, 42 insertions(+), 2 deletions(-) diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java index 52b8fb0103c..594b12e3ede 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java @@ -42,7 +42,11 @@ import java.util.Objects; * multiple times, then the line number won't provide enough context to * understand the failure. * + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} */ +@Deprecated public class Asserts { /** diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java index 69839d8e5d1..c4815229eb7 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java @@ -27,6 +27,11 @@ import java.io.FileNotFoundException; import java.nio.file.Path; import java.nio.file.Paths; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated public final class JDKToolFinder { private JDKToolFinder() { diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java index fcee2222b16..43f1ddb97d6 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java @@ -46,7 +46,10 @@ import java.util.List; * Process p = pb.start(); * } * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} */ +@Deprecated public class JDKToolLauncher { private final String executable; private final List vmArgs = new ArrayList(); diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java index 523f61c58e3..58ef07a710c 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java @@ -33,7 +33,12 @@ import java.util.regex.Pattern; /** * Utility class for verifying output and exit value from a {@code Process}. + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + * */ +@Deprecated public final class OutputAnalyzer { private final OutputBuffer output; private final String stdout; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java index 5595d5cb35c..c8a5d7aab12 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java @@ -28,6 +28,11 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated class OutputBuffer { private static class OutputBufferException extends RuntimeException { private static final long serialVersionUID = 8528687792643129571L; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java index c56697adb1b..2d9352c59b9 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java @@ -27,6 +27,11 @@ import java.io.RandomAccessFile; import java.io.FileNotFoundException; import java.io.IOException; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated public class Platform { private static final String osName = System.getProperty("os.name"); private static final String dataModel = System.getProperty("sun.arch.data.model"); diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java index 9556f22f15f..6842de26bd4 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java @@ -27,8 +27,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -42,6 +40,12 @@ import java.util.function.Predicate; import java.util.function.Consumer; import java.util.stream.Collectors; + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated public final class ProcessTools { private static final class LineForwarder extends StreamPumper.LinePump { private final PrintStream ps; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java index 7f76c6912b9..2f3c205db3c 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java @@ -34,6 +34,11 @@ import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicBoolean; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated public final class StreamPumper implements Runnable { private static final int BUF_SIZE = 256; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java index 780d704e1ef..c76339107c8 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java @@ -41,7 +41,11 @@ import java.util.function.Function; /** * Common library for various test helper functions. + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} */ +@Deprecated public final class Utils { /** From 5f8e39900cd0c35d623b41bc0f35d82019809562 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 24 Nov 2015 15:40:03 +0100 Subject: [PATCH 002/151] 8143895: Fix LDFLAGS issues after JDK-8056925 Reviewed-by: ihse --- jdk/make/launcher/Launcher-jdk.accessibility.gmk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/jdk/make/launcher/Launcher-jdk.accessibility.gmk b/jdk/make/launcher/Launcher-jdk.accessibility.gmk index 0fa486377f1..eba521c469a 100644 --- a/jdk/make/launcher/Launcher-jdk.accessibility.gmk +++ b/jdk/make/launcher/Launcher-jdk.accessibility.gmk @@ -73,8 +73,9 @@ ifeq ($(OPENJDK_TARGET_OS), windows) $$(eval $$(call SetupNativeCompilation, BUILD_JACCESSINSPECTOR$1, \ SRC := $(TOPDIR)/jaccessinspector $(TOPDIR)/common \ $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ - CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ - LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib User32.lib, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \ + LIBS := advapi32.lib user32.lib, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccessinspector$1, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ PROGRAM := jaccessinspector$1, \ @@ -100,8 +101,9 @@ ifeq ($(OPENJDK_TARGET_OS), windows) $$(eval $$(call SetupNativeCompilation,BUILD_JACCESSWALKER$1, \ SRC := $(TOPDIR)/jaccesswalker $(TOPDIR)/common \ $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ - CFLAGS :== $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ - LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib Comctl32.lib Gdi32.lib User32.lib, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \ + LIBS := advapi32.lib comctl32.lib gdi32.lib user32.lib, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccesswalker$1, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ PROGRAM := jaccesswalker$1, \ From 3c1af171595aaf96cc34750bd5e54433d55ffd9e Mon Sep 17 00:00:00 2001 From: Steven Loomis Date: Tue, 24 Nov 2015 13:36:12 -0800 Subject: [PATCH 003/151] 8068619: remove unused internal function in layout No functional change. Removes unused code. Makes JDK's layout engine have the same signature as ICU HarfBuzz's wrapper. Reviewed: http://mail.openjdk.java.net/pipermail/2d-dev/2015-March/005156.html Reviewed-by: prr --- .../libfontmanager/FontInstanceAdapter.cpp | 6 ----- .../libfontmanager/FontInstanceAdapter.h | 1 - .../libfontmanager/layout/LEFontInstance.h | 24 +------------------ 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp index 8c8c47593fb..3d133952d4d 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp @@ -67,12 +67,6 @@ FontInstanceAdapter::FontInstanceAdapter(JNIEnv *theEnv, }; -const void *FontInstanceAdapter::getFontTable(LETag tableTag) const -{ - size_t ignored = 0; - return getFontTable(tableTag, ignored); -} - static const LETag cacheMap[LAYOUTCACHE_ENTRIES] = { GPOS_TAG, GDEF_TAG, GSUB_TAG, MORT_TAG, MORX_TAG, KERN_TAG }; diff --git a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h index 8d2ee3073a0..0d8322dddbe 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h +++ b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h @@ -85,7 +85,6 @@ public: // tables are cached with the native font scaler data // only supports gsub, gpos, gdef, mort tables at present - virtual const void *getFontTable(LETag tableTag) const; virtual const void *getFontTable(LETag tableTag, size_t &len) const; virtual void *getKernPairs() const { diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h b/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h index 2baf2d6c85e..3ac687906fa 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h @@ -172,28 +172,6 @@ public: // Font file access // - /** - * This method reads a table from the font. Note that in general, - * it only makes sense to call this method on an LEFontInstance - * which represents a physical font - i.e. one which has been returned by - * getSubFont(). This is because each subfont in a composite font - * will have different tables, and there's no way to know which subfont to access. - * - * Subclasses which represent composite fonts should always return NULL. - * - * Note that implementing this function does not allow for range checking. - * Subclasses that desire the safety of range checking must implement the - * variation which has a length parameter. - * - * @param tableTag - the four byte table tag. (e.g. 'cmap') - * - * @return the address of the table in memory, or NULL - * if the table doesn't exist. - * - * @stable ICU 2.8 - */ - virtual const void *getFontTable(LETag tableTag) const = 0; - /** * This method reads a table from the font. Note that in general, * it only makes sense to call this method on an LEFontInstance @@ -213,7 +191,7 @@ public: * if the table doesn't exist. * @internal */ - virtual const void* getFontTable(LETag tableTag, size_t &length) const { length=-1; return getFontTable(tableTag); } /* -1 = unknown length */ + virtual const void* getFontTable(LETag tableTag, size_t &length) const = 0; virtual void *getKernPairs() const = 0; virtual void setKernPairs(void *pairs) const = 0; From 69b04049b56d38ae5811850c9d44a997fa6bd1d1 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 25 Nov 2015 14:44:29 +0300 Subject: [PATCH 004/151] 7063986: Wrong JNi method call in font scaler Reviewed-by: prr, rchamyal --- .../java.desktop/share/native/libfontmanager/freetypeScaler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index 5fe5372be2f..c2a294f91b7 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -258,7 +258,7 @@ Java_sun_font_FreetypeFontScaler_initNativeScaler( scalerInfo->fontData, scalerInfo->fontDataLength); if (bBuffer != NULL) { - (*env)->CallObjectMethod(env, font2D, + (*env)->CallVoidMethod(env, font2D, sunFontIDs.readFileMID, bBuffer); error = FT_New_Memory_Face(scalerInfo->library, From bcb678575580e78beb157c5706c10b4ea521250a Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Thu, 26 Nov 2015 19:12:28 +0400 Subject: [PATCH 005/151] 8055197: TextField deletes multiline strings Reviewed-by: serb, alexsch --- .../share/classes/java/awt/TextField.java | 21 +- .../java/awt/TextField/EOLTest/EOLTest.java | 202 ++++++++++++++++++ 2 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/TextField/EOLTest/EOLTest.java diff --git a/jdk/src/java.desktop/share/classes/java/awt/TextField.java b/jdk/src/java.desktop/share/classes/java/awt/TextField.java index de6b5cda6d4..2dfd19c4128 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/TextField.java +++ b/jdk/src/java.desktop/share/classes/java/awt/TextField.java @@ -198,7 +198,7 @@ public class TextField extends TextComponent { * @see java.awt.GraphicsEnvironment#isHeadless */ public TextField(String text, int columns) throws HeadlessException { - super(text); + super(replaceEOL(text)); this.columns = (columns >= 0) ? columns : 0; } @@ -297,12 +297,28 @@ public class TextField extends TextComponent { * @see java.awt.TextComponent#getText */ public void setText(String t) { - super.setText(t); + super.setText(replaceEOL(t)); // This could change the preferred size of the Component. invalidateIfValid(); } + /** + * Replaces EOL characters from the text variable with a space character. + * @param text the new text. + * @return Returns text after replacing EOL characters. + */ + private static String replaceEOL(String text) { + String[] strEOLs = {System.lineSeparator(), "\n"}; + for (String eol : strEOLs) { + if (text.contains(eol)) { + text = text.replace(eol, " "); + } + } + return text; + } + + /** * Indicates whether or not this text field has a * character set for echoing. @@ -704,6 +720,7 @@ public class TextField extends TextComponent { { // HeadlessException will be thrown by TextComponent's readObject s.defaultReadObject(); + text = replaceEOL(text); // Make sure the state we just read in for columns has legal values if (columns < 0) { diff --git a/jdk/test/java/awt/TextField/EOLTest/EOLTest.java b/jdk/test/java/awt/TextField/EOLTest/EOLTest.java new file mode 100644 index 00000000000..a9ab7b0941d --- /dev/null +++ b/jdk/test/java/awt/TextField/EOLTest/EOLTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8055197 7186036 + @summary TextField should replace EOL character with space character + @run main EOLTest + */ + +import java.awt.Frame; +import java.awt.TextField; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; + +public class EOLTest { + + private Frame mainFrame; + private TextField textField; + private String testStrEOL; + private boolean isTestFail; + private int testFailCount; + StringBuilder testFailMessage; + private String expectedString = "Row1 Row2 Row3"; + + public EOLTest() { + mainFrame = new Frame(); + mainFrame.setSize(200, 200); + mainFrame.setVisible(true); + testFailMessage = new StringBuilder(); + testStrEOL = "Row1" + System.lineSeparator() + "Row2\nRow3"; + } + + private void testConstructor1() { + textField = new TextField(testStrEOL); + textField.setSize(200, 100); + mainFrame.add(textField); + checkTest(); + mainFrame.remove(textField); + } + + private void testConstructor2() { + textField = new TextField(30); + textField.setSize(200, 100); + mainFrame.add(textField); + textField.setText(testStrEOL); + checkTest(); + mainFrame.remove(textField); + } + + private void testConstructor3() { + textField = new TextField(testStrEOL, 30); + textField.setSize(200, 100); + mainFrame.add(textField); + checkTest(); + mainFrame.remove(textField); + } + + private void testSetText() { + textField = new TextField(); + textField.setSize(200, 100); + textField.setText(testStrEOL); + mainFrame.add(textField); + checkTest(); + mainFrame.remove(textField); + } + + private void testDeserialization() { + TextField textFieldToSerialize = new TextField(testStrEOL); + textFieldToSerialize.setSize(200, 100); + mainFrame.add(textFieldToSerialize); + try { + // Serialize TextField object "textFieldToSerialize". + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutput outStream = new ObjectOutputStream(baos); + outStream.writeObject(textFieldToSerialize); + + // Search the text variable data through serialized object stream. + byte[] streamedBytes = baos.toByteArray(); + int foundLoc = 0; + for (int i = 0; i < streamedBytes.length; ++i) { + if (streamedBytes[i] == expectedString.charAt(0)) { + foundLoc = i; + int j = 1; + for (; j < expectedString.length(); ++j) { + if (streamedBytes[i+j] != expectedString.charAt(j)) { + break; + } + } + if (j == expectedString.length()) { + break; + } + } + foundLoc = -1; + } + + if (foundLoc == -1) { + // Could not find text data in serialized object stream. + throw new Exception("Could not find text data in serialized " + + "object stream."); + } + // Replace space character from serialized stream with + // EOL character for testing de-serialization. + String EOLChar = System.lineSeparator(); + String newExpectedString = ""; + for (int i = foundLoc, j = 0; j < expectedString.length(); ++i, ++j) { + newExpectedString += (char)(streamedBytes[i]); + if (streamedBytes[i] == ' ') { + int k = 0; + for (; k < EOLChar.length(); ++k) { + streamedBytes[i + k] = (byte) EOLChar.charAt(k); + } + i += k-1; + j += k-1; + } + } + // New line character varies with platform, + // ex. For windows '\r\n', for linux '\n'. + // While replacing space from serialized object stream, the length + // of EOL character will affect the expected string as well. + expectedString = newExpectedString; + + // De-serialize TextField object stream. + ByteArrayInputStream bais = new ByteArrayInputStream(streamedBytes); + ObjectInput inStream = new ObjectInputStream(bais); + textField = (TextField) inStream.readObject(); + } catch (Exception ex) { + // Serialization or De-serialization failed. + // Create textField with empty string to show failure. + ex.printStackTrace(); + textField = new TextField(); + } + + checkTest(); + mainFrame.remove(textFieldToSerialize); + } + + private void checkTest() { + if (!textField.getText().equals(expectedString)) { + testFailMessage.append("TestFail line : "); + testFailMessage.append(Thread.currentThread().getStackTrace()[2]. + getLineNumber()); + testFailMessage.append(" TextField.getText() : \""); + testFailMessage.append(textField.getText()); + testFailMessage.append("\" does not match expected string : \""); + testFailMessage.append(expectedString).append("\""); + testFailMessage.append(System.getProperty("line.separator")); + testFailCount++; + isTestFail = true; + } + } + + private void checkFailures() { + if (isTestFail) { + testFailMessage.insert(0, "Test Fail count : " + testFailCount + + System.getProperty("line.separator")); + dispose(); + throw new RuntimeException(testFailMessage.toString()); + } + } + + private void dispose() { + if (mainFrame != null) { + mainFrame.dispose(); + } + } + + public static void main(String[] args) { + EOLTest testEOL = new EOLTest(); + testEOL.testConstructor1(); + testEOL.testConstructor2(); + testEOL.testConstructor3(); + testEOL.testSetText(); + testEOL.testDeserialization(); + testEOL.checkFailures(); + testEOL.dispose(); + } +} \ No newline at end of file From 39ce42b41e470034869b79d8ab1fdcde1456477b Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 1 Dec 2015 19:02:50 +0300 Subject: [PATCH 006/151] 8081457: TrayIcon tests fail in OEL 7 only Reviewed-by: alexsch, serb, azvegint --- .../classes/sun/awt/X11/XTrayIconPeer.java | 1 + .../TrayIcon/ActionCommand/ActionCommand.java | 7 +- .../ActionEventMask/ActionEventMask.java | 6 +- .../TrayIcon/ModalityTest/ModalityTest.java | 66 ++++++++++++------ .../MouseEventMask/MouseEventMaskTest.java | 4 +- .../MouseMovedTest/MouseMovedTest.java | 12 +++- .../FunctionalityCheck.java | 69 ++++++++++++------- .../FunctionalityCheck/tray.policy | 2 + .../awt/TrayIcon/SystemTrayIconHelper.java | 42 ++++++++++- .../TrayIconEventModifiersTest.java | 8 ++- .../TrayIconEvents/TrayIconEventsTest.java | 67 ++++++++++++------ .../TrayIconMouseTest/TrayIconMouseTest.java | 10 ++- .../TrayIconPopup/TrayIconPopupTest.java | 4 +- 13 files changed, 217 insertions(+), 81 deletions(-) diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java index eba30a7e2af..20b7a9d7899 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java @@ -413,6 +413,7 @@ public class XTrayIconPeer implements TrayIconPeer, void addListeners() { canvas.addMouseListener(eventProxy); canvas.addMouseMotionListener(eventProxy); + eframe.addMouseListener(eventProxy); } long getWindow() { diff --git a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java index 5c5a17e0dbc..ce5495e3585 100644 --- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java +++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -59,8 +59,11 @@ public class ActionCommand { "and rerun test."); } else if (System.getProperty("os.name").toLowerCase().startsWith("mac")){ isMacOS = true; + } else if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support double click in " + + "systray. Skipped"); + return; } - new ActionCommand().doTest(); } } diff --git a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java index fb95874eadc..ebafe40e282 100644 --- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java +++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -66,6 +66,10 @@ public class ActionEventMask { } else { if (System.getProperty("os.name").toLowerCase().startsWith("mac")) { isMacOS = true; + } else if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support double click in " + + "systray. Skipped"); + return; } new ActionEventMask().doTest(); } diff --git a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java index 2118457ee79..4c0bb1d3c4a 100644 --- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java +++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -35,6 +35,7 @@ import java.awt.image.BufferedImage; */ public class ModalityTest { + private static boolean isOEL7; TrayIcon icon; ExtendedRobot robot; Dialog d; @@ -80,7 +81,7 @@ public class ModalityTest { "\"Always show all icons and notifications on the taskbar\" true " + "to avoid this problem. Or change behavior only for Java SE tray " + "icon and rerun test."); - + isOEL7 = SystemTrayIconHelper.isOel7(); new ModalityTest().doTest(); } } @@ -225,6 +226,12 @@ public class ModalityTest { Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) throw new RuntimeException("Unable to find the icon location!"); + if (isOEL7) { + // close tray + robot.mouseMove(100,100); + robot.click(InputEvent.BUTTON1_MASK); + robot.waitForIdle(2000); + } if (! d.isVisible()) throw new RuntimeException("FAIL: The modal dialog is not yet visible"); @@ -232,27 +239,35 @@ public class ModalityTest { robot.mouseMove(iconPosition.x, iconPosition.y); robot.waitForIdle(2000); - SystemTrayIconHelper.doubleClick(robot); + if(!isOEL7) { + SystemTrayIconHelper.doubleClick(robot); - if (! actionPerformed) { - synchronized (actionLock) { - try { - actionLock.wait(3000); - } catch (Exception e) { + if (!actionPerformed) { + synchronized (actionLock) { + try { + actionLock.wait(3000); + } catch (Exception e) { + } } } + if (!actionPerformed) + throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); } - if (! actionPerformed) - throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); for (int i = 0; i < buttonTypes.length; i++) { mousePressed = false; - robot.mousePress(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mousePress(buttonTypes[i]); + } if (! mousePressed) { synchronized (pressLock) { try { - pressLock.wait(3000); + pressLock.wait(6000); } catch (Exception e) { } } @@ -264,12 +279,18 @@ public class ModalityTest { mouseReleased = false; mouseClicked = false; - robot.mouseRelease(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mouseRelease(buttonTypes[i]); + } if (! mouseReleased) { synchronized (releaseLock) { try { - releaseLock.wait(3000); + releaseLock.wait(6000); } catch (Exception e) { } } @@ -281,7 +302,7 @@ public class ModalityTest { if (! mouseClicked) { synchronized (clickLock) { try { - clickLock.wait(3000); + clickLock.wait(6000); } catch (Exception e) { } } @@ -290,13 +311,14 @@ public class ModalityTest { throw new RuntimeException("FAIL: mouseClicked not triggered when " + buttonNames[i] + " pressed & released"); } + if (!isOEL7) { + mouseMoved = false; + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.glide(iconPosition.x + 100, iconPosition.y); - mouseMoved = false; - robot.mouseMove(iconPosition.x, iconPosition.y); - robot.glide(iconPosition.x + 100, iconPosition.y); - - if (! mouseMoved) - if (! SystemTrayIconHelper.skip(0) ) - throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + if (!mouseMoved) + if (!SystemTrayIconHelper.skip(0)) + throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + } } } diff --git a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java index e6c194ec69c..113ec7e9d71 100644 --- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java +++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -71,6 +71,8 @@ public class MouseEventMaskTest { "\"Always show all icons and notifications on the taskbar\" true " + "to avoid this problem. Or change behavior only for Java SE tray " + "icon and rerun test."); + } else if (SystemTrayIconHelper.isOel7()) { + return; } new MouseEventMaskTest().doTest(); } diff --git a/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java b/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java index 04d91f23859..d6e6d760f79 100644 --- a/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java +++ b/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,7 @@ import java.awt.image.BufferedImage; * @summary Check for mouseMoved event for java.awt.TrayIcon * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) * @library ../../../../lib/testlibrary - * @build ExtendedRobot + * @build ExtendedRobot SystemTrayIconHelper * @run main MouseMovedTest */ @@ -39,6 +39,14 @@ public class MouseMovedTest { static volatile boolean moved; public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + return; + } + + if (SystemTrayIconHelper.isOel7()) { + return; + } + moved = false; TrayIcon icon = new TrayIcon(new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB), "Test icon"); diff --git a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java index 5918ac3dfc0..c9d2eade8c3 100644 --- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java +++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -51,6 +51,7 @@ public class FunctionalityCheck { boolean mouseReleased = false; boolean mouseClicked = false; boolean mouseMoved = false; + static boolean isOEL7; static final int[] buttonTypes = { InputEvent.BUTTON1_MASK, @@ -69,6 +70,7 @@ public class FunctionalityCheck { System.out.println("SystemTray not supported on the platform under test. " + "Marking the test passed"); } else { + isOEL7 = SystemTrayIconHelper.isOel7(); new FunctionalityCheck().doTest(); } } @@ -188,31 +190,44 @@ public class FunctionalityCheck { Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) throw new RuntimeException("Unable to find the icon location!"); + if (isOEL7) { + // close tray + robot.mouseMove(100,100); + robot.click(InputEvent.BUTTON1_MASK); + robot.waitForIdle(2000); + } robot.mouseMove(iconPosition.x, iconPosition.y); - robot.waitForIdle(2000); + robot.waitForIdle(); + if(!isOEL7) { + SystemTrayIconHelper.doubleClick(robot); - SystemTrayIconHelper.doubleClick(robot); - - if (! actionPerformed) { - synchronized (actionLock) { - try { - actionLock.wait(3000); - } catch (Exception e) { + if (!actionPerformed) { + synchronized (actionLock) { + try { + actionLock.wait(3000); + } catch (Exception e) { + } } } + if (!actionPerformed) + throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); } - if (! actionPerformed) - throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); for (int i = 0; i < buttonTypes.length; i++) { mousePressed = false; - robot.mousePress(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mousePress(buttonTypes[i]); + } if (! mousePressed) { synchronized (pressLock) { try { - pressLock.wait(3000); + pressLock.wait(6000); } catch (Exception e) { } } @@ -224,12 +239,17 @@ public class FunctionalityCheck { mouseReleased = false; mouseClicked = false; - robot.mouseRelease(buttonTypes[i]); - + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mouseRelease(buttonTypes[i]); + } if (! mouseReleased) { synchronized (releaseLock) { try { - releaseLock.wait(3000); + releaseLock.wait(6000); } catch (Exception e) { } } @@ -242,7 +262,7 @@ public class FunctionalityCheck { if (! mouseClicked) { synchronized (clickLock) { try { - clickLock.wait(3000); + clickLock.wait(6000); } catch (Exception e) { } } @@ -251,13 +271,14 @@ public class FunctionalityCheck { throw new RuntimeException("FAIL: mouseClicked not triggered when " + buttonNames[i] + " pressed & released"); } + if(!isOEL7) { + mouseMoved = false; + robot.mouseMove(iconPosition.x + 100, iconPosition.y); + robot.glide(iconPosition.x, iconPosition.y); - mouseMoved = false; - robot.mouseMove(iconPosition.x + 100, iconPosition.y); - robot.glide(iconPosition.x, iconPosition.y); - - if (! mouseMoved) - if (! SystemTrayIconHelper.skip(0) ) - throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + if (!mouseMoved) + if (!SystemTrayIconHelper.skip(0)) + throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + } } } diff --git a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy index 845bfb8d80b..c2c76434cd3 100644 --- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy +++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy @@ -5,6 +5,7 @@ grant { permission java.util.PropertyPermission "resultsDir", "read"; permission java.util.PropertyPermission "user.home", "read"; permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.version", "read"; permission java.awt.AWTPermission "accessEventQueue"; permission java.lang.RuntimePermission "setIO"; permission java.lang.RuntimePermission "accessDeclaredMembers"; @@ -17,5 +18,6 @@ grant { permission java.util.PropertyPermission "java.class.path", "read"; permission java.awt.AWTPermission "readDisplayPixels"; permission java.awt.AWTPermission "watchMousePointer"; + }; diff --git a/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java b/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java index a8f6e2f7cf5..cb36b8fdba3 100644 --- a/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java +++ b/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java @@ -66,7 +66,9 @@ public class SystemTrayIconHelper { for (int x = (int) (screenSize.getWidth()-width); x > 0; x--) { for (int y = (int) (screenSize.getHeight()-height); y > (screenSize.getHeight()-50); y--) { if (imagesEquals(((BufferedImage)icon.getImage()).getSubimage(0, 0, width, height), screen.getSubimage(x, y, width, height))) { - return new Point(x+5, y+5); + Point point = new Point(x + 5, y + 5); + System.out.println("Icon location " + point); + return point; } } } @@ -91,6 +93,7 @@ public class SystemTrayIconHelper { point2d = (Point2D)m_getLocation.invoke(peer, new Object[]{model}); Point po = new Point((int)(point2d.getX()), (int)(point2d.getY())); po.translate(10, -5); + System.out.println("Icon location " + po); return po; }catch(Exception e) { e.printStackTrace(); @@ -101,12 +104,15 @@ public class SystemTrayIconHelper { // sun.awt.X11.XTrayIconPeer Field f_peer = getField(java.awt.TrayIcon.class, "peer"); + SystemTrayIconHelper.openTrayIfNeeded(robot); + Object peer = f_peer.get(icon); Method m_getLOS = peer.getClass().getDeclaredMethod( "getLocationOnScreen", new Class[]{}); m_getLOS.setAccessible(true); Point point = (Point)m_getLOS.invoke(peer, new Object[]{}); point.translate(5, 5); + System.out.println("Icon location " + point); return point; } catch (Exception e) { e.printStackTrace(); @@ -169,4 +175,38 @@ public class SystemTrayIconHelper { } return false; } + + public static boolean openTrayIfNeeded(Robot robot) { + String sysv = System.getProperty("os.version"); + System.out.println("System version is " + sysv); + //Additional step to raise the system try in Gnome 3 in OEL 7 + if(isOel7()) { + System.out.println("OEL 7 detected"); + GraphicsConfiguration gc = GraphicsEnvironment. + getLocalGraphicsEnvironment().getDefaultScreenDevice(). + getDefaultConfiguration(); + Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + if(insets.bottom > 0) { + Dimension screenSize = Toolkit.getDefaultToolkit() + .getScreenSize(); + robot.mouseMove(screenSize.width - insets.bottom / 2, + screenSize.height - insets.bottom / 2); + robot.delay(50); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(50); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + robot.delay(1000); + System.out.println("Tray is opened"); + return true; + } + } + return false; + } + + public static boolean isOel7() { + return System.getProperty("os.name").toLowerCase() + .contains("linux") && System.getProperty("os.version") + .toLowerCase().contains("el7"); + } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java index 9cdce634a92..b80db75b510 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -121,6 +121,12 @@ public class TrayIconEventModifiersTest { }; } + if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support click modifiers in " + + "systray. Skipped"); + return; + } + new TrayIconEventModifiersTest().doTest(); } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java index c7c79ea6570..275e51065ca 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -37,6 +37,7 @@ import java.awt.image.BufferedImage; public class TrayIconEventsTest { + private static boolean isOEL7; TrayIcon icon; ExtendedRobot robot; @@ -77,6 +78,7 @@ public class TrayIconEventsTest { "\"Always show all icons and notifications on the taskbar\" true " + "to avoid this problem. Or change behavior only for Java SE " + "tray icon."); + isOEL7 = SystemTrayIconHelper.isOel7(); new TrayIconEventsTest().doTest(); } } @@ -195,31 +197,44 @@ public class TrayIconEventsTest { Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) throw new RuntimeException("Unable to find the icon location!"); + if (isOEL7) { + // close tray + robot.mouseMove(100,100); + robot.click(InputEvent.BUTTON1_MASK); + robot.waitForIdle(2000); + } robot.mouseMove(iconPosition.x, iconPosition.y); - robot.waitForIdle(2000); + robot.waitForIdle(); + if(!isOEL7) { + SystemTrayIconHelper.doubleClick(robot); - SystemTrayIconHelper.doubleClick(robot); - - if (! actionPerformed) { - synchronized (actionLock) { - try { - actionLock.wait(10000); - } catch (Exception e) { + if (!actionPerformed) { + synchronized (actionLock) { + try { + actionLock.wait(10000); + } catch (Exception e) { + } } } + if (!actionPerformed) + throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); } - if (! actionPerformed) - throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); for (int i = 0; i < buttonTypes.length; i++) { mousePressed = false; - robot.mousePress(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mousePress(buttonTypes[i]); + } if (! mousePressed) { synchronized (pressLock) { try { - pressLock.wait(3000); + pressLock.wait(6000); } catch (Exception e) { } } @@ -231,12 +246,18 @@ public class TrayIconEventsTest { mouseReleased = false; mouseClicked = false; - robot.mouseRelease(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mouseRelease(buttonTypes[i]); + } if (! mouseReleased) { synchronized (releaseLock) { try { - releaseLock.wait(3000); + releaseLock.wait(6000); } catch (Exception e) { } } @@ -248,7 +269,7 @@ public class TrayIconEventsTest { if (! mouseClicked) { synchronized (clickLock) { try { - clickLock.wait(3000); + clickLock.wait(6000); } catch (Exception e) { } } @@ -258,12 +279,14 @@ public class TrayIconEventsTest { buttonNames[i] + " pressed & released"); } - mouseMoved = false; - robot.mouseMove(iconPosition.x + 100, iconPosition.y); - robot.glide(iconPosition.x, iconPosition.y); + if (!isOEL7) { + mouseMoved = false; + robot.mouseMove(iconPosition.x + 100, iconPosition.y); + robot.glide(iconPosition.x, iconPosition.y); - if (! mouseMoved) - if (! SystemTrayIconHelper.skip(0) ) - throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + if (!mouseMoved) + if (!SystemTrayIconHelper.skip(0)) + throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + } } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java index 124ceba5399..b8f6a69d30c 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -66,6 +66,10 @@ public class TrayIconMouseTest { } else { if (System.getProperty("os.name").toLowerCase().startsWith("mac")) { isMacOS = true; + } else if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support double click in " + + "systray. Skipped"); + return; } new TrayIconMouseTest().doTest(); } @@ -108,7 +112,7 @@ public class TrayIconMouseTest { for (int i = 0; i < buttonTypes.length; i++) { actionPerformed = false; robot.click(buttonTypes[i]); - robot.waitForIdle(2000); + robot.waitForIdle(6000); if (isMacOS && actionPerformed && i == 2) { @@ -155,7 +159,7 @@ public class TrayIconMouseTest { if (! actionPerformed) { synchronized (actionLock) { try { - actionLock.wait(3000); + actionLock.wait(6000); } catch (Exception e) { } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java index f866cc18aa0..a81e516bd0e 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -127,7 +127,7 @@ public class TrayIconPopupTest { robot.mousePress(InputEvent.BUTTON3_MASK); robot.delay(50); robot.mouseRelease(InputEvent.BUTTON3_MASK); - robot.delay(1000); + robot.delay(6000); robot.mouseMove(window.getLocation().x + 10, window.getLocation().y + 10); robot.mousePress(InputEvent.BUTTON3_MASK); From afabb1b2c0e38ad2f124489faab54456d85b9c96 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 1 Dec 2015 19:07:45 +0300 Subject: [PATCH 007/151] 8068228: Test closed/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest fails with GTKLookAndFeel Reviewed-by: ssadetsky, arapte --- .../MaximizedFrameTest.html | 42 ---- .../MaximizedFrameTest.java | 200 +++++++++++------- 2 files changed, 129 insertions(+), 113 deletions(-) delete mode 100644 jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html diff --git a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html deleted file mode 100644 index 97781dc7643..00000000000 --- a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - - - - - - -

bug 6176814
Bug ID: 6176814

- -

This is an AUTOMATIC test, simply wait for completion

- - - - diff --git a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java index c2ee806bb19..e519d3dad19 100644 --- a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java +++ b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -22,91 +22,149 @@ */ /* - test - @bug 6176814 - @summary Metalworks frame maximizes after the move - @author Andrei.Dmitriev area=Event - @run applet MaximizedFrameTest.html -*/ + @test + @bug 6176814 8132766 + @summary Metalworks frame maximizes after the move + @run main MaximizedFrameTest + */ -import java.applet.Applet; -import javax.swing.*; -import java.awt.event.*; -import java.awt.*; +import java.awt.AWTException; +import java.awt.Component; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; -public class MaximizedFrameTest extends Applet -{ - final int ITERATIONS_COUNT = 20; - Robot robot; - Point framePosition; - Point newFrameLocation; - JFrame frame; - Rectangle gcBounds; - public static Object LOCK = new Object(); +public class MaximizedFrameTest { - public void init() - { - String[] instructions = - { - "This is an AUTOMATIC test", - "simply wait until it is done" - }; + final static int ITERATIONS_COUNT = 5; + private static JFrame frame; + private static Point tempMousePosition; + private static Component titleComponent; + + public void init() { JFrame.setDefaultLookAndFeelDecorated(true); + + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException | UnsupportedLookAndFeelException ex) { + throw new RuntimeException("Test Failed. MetalLookAndFeel not set " + + "for frame"); + } + frame = new JFrame("JFrame Maximization Test"); frame.pack(); frame.setSize(450, 260); - }//End init() - - public void start () - { frame.setVisible(true); - validate(); - JLayeredPane lPane = frame.getLayeredPane(); - // System.out.println("JFrame's LayeredPane " + lPane ); - Component titleComponent = null; - boolean titleFound = false; - for (int j=0; j < lPane.getComponentsInLayer(JLayeredPane.FRAME_CONTENT_LAYER.intValue()).length; j++){ - titleComponent = lPane.getComponentsInLayer(JLayeredPane.FRAME_CONTENT_LAYER.intValue())[j]; - if (titleComponent.getClass().getName().equals("javax.swing.plaf.metal.MetalTitlePane")){ - titleFound = true; - break; + } + + public void getTitleComponent() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + JLayeredPane lPane = frame.getLayeredPane(); + boolean titleFound = false; + + for (int j = 0; j < lPane.getComponentsInLayer( + JLayeredPane.FRAME_CONTENT_LAYER.intValue()).length; j++) { + + titleComponent = lPane.getComponentsInLayer( + JLayeredPane.FRAME_CONTENT_LAYER.intValue())[j]; + + if (titleComponent.getClass().getName().equals( + "javax.swing.plaf.metal.MetalTitlePane")) { + + titleFound = true; + break; + } + } + + if (!titleFound) { + try { + dispose(); + } catch (Exception ex) { + Logger.getLogger(MaximizedFrameTest.class.getName()) + .log(Level.SEVERE, null, ex); + } + throw new RuntimeException("Test Failed. Unable to " + + "determine title component"); + } } - } - if ( !titleFound ){ - throw new RuntimeException("Test Failed. Unable to determine title's size."); - } - //-------------------------------- - // it is sufficient to get maximized Frame only once. - Point tempMousePosition; - framePosition = frame.getLocationOnScreen(); + }); + } + + public void doMaximizeFrameTest() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Point framePosition = frame.getLocationOnScreen(); + + tempMousePosition = new Point(framePosition.x + + frame.getWidth() / 2, framePosition.y + + titleComponent.getHeight() / 2); + } + }); + try { - robot = new Robot(); - tempMousePosition = new Point(framePosition.x + - frame.getWidth()/2, - framePosition.y + - titleComponent.getHeight()/2); + Robot robot = new Robot(); robot.mouseMove(tempMousePosition.x, tempMousePosition.y); - for (int iteration=0; iteration < ITERATIONS_COUNT; iteration++){ + robot.waitForIdle(); + + for (int iteration = 0; iteration < ITERATIONS_COUNT; iteration++) { robot.mousePress(InputEvent.BUTTON1_MASK); - gcBounds = - GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getConfigurations()[0].getBounds(); - //Moving a mouse pointer less than a few pixels - //leads to rising a double click event. - //We have to use exceeded the AWT_MULTICLICK_SMUDGE - //const value (which is 4 by default on GNOME) to test that. + robot.waitForIdle(); + + // Moving a mouse pointer less than a few pixels + // leads to rising a double click event. + // We have to use exceeded the AWT_MULTICLICK_SMUDGE + // const value (which is 4 by default on GNOME) to test that. tempMousePosition.x += 5; robot.mouseMove(tempMousePosition.x, tempMousePosition.y); - robot.delay(70); + robot.waitForIdle(); robot.mouseRelease(InputEvent.BUTTON1_MASK); - if ( frame.getExtendedState() != 0 ){ - throw new RuntimeException ("Test failed. JFrame was maximized. ExtendedState is : "+frame.getExtendedState()); - } - robot.delay(500); - } //for iteration + robot.waitForIdle(); - }catch(AWTException e) { - throw new RuntimeException("Test Failed. AWTException thrown."); + if (frame.getExtendedState() != 0) { + dispose(); + throw new RuntimeException("Test failed. JFrame was " + + "maximized. ExtendedState is : " + + frame.getExtendedState()); + } } + } catch (AWTException e) { + dispose(); + throw new RuntimeException("Test Failed. AWTException thrown."); + } System.out.println("Test passed."); - }// start() -}// class + } + + private void dispose() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (null != frame) { + frame.dispose(); + } + } + }); + } + + public static void main(String[] args) throws Exception { + + MaximizedFrameTest maximizedFrameTest = new MaximizedFrameTest(); + maximizedFrameTest.init(); + maximizedFrameTest.getTitleComponent(); + maximizedFrameTest.doMaximizeFrameTest(); + maximizedFrameTest.dispose(); + } +} From 39b6389c6da36985bead96afefc1c68a5fcd2690 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 1 Dec 2015 19:21:40 +0300 Subject: [PATCH 008/151] 8030702: Deadlock between subclass of AbstractDocument and UndoManager Reviewed-by: alexsch, azvegint --- .../javax/swing/text/AbstractDocument.java | 88 +++++++++++++ .../classes/javax/swing/undo/UndoManager.java | 119 +++++++++++++---- .../swing/text/UndoableEditLockSupport.java | 43 ++++++ .../AbstractDocumentUndoConcurrentTest.java | 122 ++++++++++++++++++ 4 files changed, 346 insertions(+), 26 deletions(-) create mode 100644 jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java create mode 100644 jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java index 2b87618abd9..b965ccfcbc0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java @@ -36,6 +36,7 @@ import javax.swing.tree.TreeNode; import sun.font.BidiUtils; import sun.swing.SwingUtilities2; +import sun.swing.text.UndoableEditLockSupport; /** * An implementation of the document interface to serve as a @@ -275,6 +276,11 @@ public abstract class AbstractDocument implements Document, Serializable { * @see EventListenerList */ protected void fireUndoableEditUpdate(UndoableEditEvent e) { + if (e.getEdit() instanceof DefaultDocumentEvent) { + e = new UndoableEditEvent(e.getSource(), + new DefaultDocumentEventUndoableWrapper( + (DefaultDocumentEvent)e.getEdit())); + } // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying @@ -2952,6 +2958,88 @@ public abstract class AbstractDocument implements Document, Serializable { } + static class DefaultDocumentEventUndoableWrapper implements + UndoableEdit, UndoableEditLockSupport + { + final DefaultDocumentEvent dde; + public DefaultDocumentEventUndoableWrapper(DefaultDocumentEvent dde) { + this.dde = dde; + } + + @Override + public void undo() throws CannotUndoException { + dde.undo(); + } + + @Override + public boolean canUndo() { + return dde.canUndo(); + } + + @Override + public void redo() throws CannotRedoException { + dde.redo(); + } + + @Override + public boolean canRedo() { + return dde.canRedo(); + } + + @Override + public void die() { + dde.die(); + } + + @Override + public boolean addEdit(UndoableEdit anEdit) { + return dde.addEdit(anEdit); + } + + @Override + public boolean replaceEdit(UndoableEdit anEdit) { + return dde.replaceEdit(anEdit); + } + + @Override + public boolean isSignificant() { + return dde.isSignificant(); + } + + @Override + public String getPresentationName() { + return dde.getPresentationName(); + } + + @Override + public String getUndoPresentationName() { + return dde.getUndoPresentationName(); + } + + @Override + public String getRedoPresentationName() { + return dde.getRedoPresentationName(); + } + + /** + * {@inheritDoc} + * @since 1.9 + */ + @Override + public void lockEdit() { + ((AbstractDocument)dde.getDocument()).writeLock(); + } + + /** + * {@inheritDoc} + * @since 1.9 + */ + @Override + public void unlockEdit() { + ((AbstractDocument)dde.getDocument()).writeUnlock(); + } + } + /** * This event used when firing document changes while Undo/Redo * operations. It just wraps DefaultDocumentEvent and delegates diff --git a/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java b/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java index 782dd3b3356..cb85826e611 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,6 +28,7 @@ package javax.swing.undo; import javax.swing.event.*; import javax.swing.UIManager; import java.util.*; +import sun.swing.text.UndoableEditLockSupport; /** * {@code UndoManager} manages a list of {@code UndoableEdits}, @@ -134,6 +135,11 @@ import java.util.*; */ @SuppressWarnings("serial") // Same-version serialization only public class UndoManager extends CompoundEdit implements UndoableEditListener { + private enum Action { + UNDO, + REDO, + ANY + } int indexOfNextAdd; int limit; @@ -369,13 +375,8 @@ public class UndoManager extends CompoundEdit implements UndoableEditListener { * @throws CannotRedoException if one of the edits throws * CannotRedoException */ - public synchronized void undoOrRedo() throws CannotRedoException, - CannotUndoException { - if (indexOfNextAdd == edits.size()) { - undo(); - } else { - redo(); - } + public void undoOrRedo() throws CannotRedoException, CannotUndoException { + tryUndoOrRedo(Action.ANY); } /** @@ -407,16 +408,8 @@ public class UndoManager extends CompoundEdit implements UndoableEditListener { * @see #canUndo * @see #editToBeUndone */ - public synchronized void undo() throws CannotUndoException { - if (inProgress) { - UndoableEdit edit = editToBeUndone(); - if (edit == null) { - throw new CannotUndoException(); - } - undoTo(edit); - } else { - super.undo(); - } + public void undo() throws CannotUndoException { + tryUndoOrRedo(Action.UNDO); } /** @@ -452,16 +445,90 @@ public class UndoManager extends CompoundEdit implements UndoableEditListener { * @see #canRedo * @see #editToBeRedone */ - public synchronized void redo() throws CannotRedoException { - if (inProgress) { - UndoableEdit edit = editToBeRedone(); - if (edit == null) { - throw new CannotRedoException(); + public void redo() throws CannotRedoException { + tryUndoOrRedo(Action.REDO); + } + + private void tryUndoOrRedo(Action action) { + UndoableEditLockSupport lockSupport = null; + boolean undo; + synchronized (this) { + if (action == Action.ANY) { + undo = indexOfNextAdd == edits.size(); + } else { + undo = action == Action.UNDO; + } + if (inProgress) { + UndoableEdit edit = undo ? editToBeUndone() : editToBeRedone(); + if (edit == null) { + throw undo ? new CannotUndoException() : + new CannotRedoException(); + } + lockSupport = getEditLockSupport(edit); + if (lockSupport == null) { + if (undo) { + undoTo(edit); + } else { + redoTo(edit); + } + return; + } + } else { + if (undo) { + super.undo(); + } else { + super.redo(); + } + return; } - redoTo(edit); - } else { - super.redo(); } + // the edit synchronization is required + while (true) { + lockSupport.lockEdit(); + UndoableEditLockSupport editLockSupport = null; + try { + synchronized (this) { + if (action == Action.ANY) { + undo = indexOfNextAdd == edits.size(); + } + if (inProgress) { + UndoableEdit edit = undo ? editToBeUndone() : + editToBeRedone(); + if (edit == null) { + throw undo ? new CannotUndoException() : + new CannotRedoException(); + } + editLockSupport = getEditLockSupport(edit); + if (editLockSupport == null || + editLockSupport == lockSupport) { + if (undo) { + undoTo(edit); + } else { + redoTo(edit); + } + return; + } + } else { + if (undo) { + super.undo(); + } else { + super.redo(); + } + return; + } + } + } finally { + if (lockSupport != null) { + lockSupport.unlockEdit(); + } + lockSupport = editLockSupport; + } + } + } + + private UndoableEditLockSupport getEditLockSupport(UndoableEdit anEdit) { + return anEdit instanceof UndoableEditLockSupport ? + (UndoableEditLockSupport)anEdit : null; } /** diff --git a/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java b/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java new file mode 100644 index 00000000000..43440da0dc8 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.swing.text; + +import javax.swing.undo.UndoableEdit; + +/** + * UndoableEdit support for undo/redo actions synchronization + * @since 1.9 + */ +public interface UndoableEditLockSupport extends UndoableEdit { + /** + * lock the UndoableEdit for threadsafe undo/redo + */ + void lockEdit(); + + /** + * unlock the UndoableEdit + */ + void unlockEdit(); +} diff --git a/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java new file mode 100644 index 00000000000..30c48df47f8 --- /dev/null +++ b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8030702 + @summary Deadlock between subclass of AbstractDocument and UndoManager + @author Semyon Sadetsky + */ + +import javax.swing.text.PlainDocument; +import javax.swing.text.StringContent; +import javax.swing.undo.UndoManager; +import java.text.DecimalFormat; +import java.text.Format; +import java.util.concurrent.CyclicBarrier; + +public class AbstractDocumentUndoConcurrentTest { + static CyclicBarrier barrier = new CyclicBarrier(3); + + private static PlainDocument doc1; + private static PlainDocument doc2; + private static Format format1 = new DecimalFormat(""); + private static Format format2 = new DecimalFormat(""); + + public static void main(String[] args) throws Exception { + test(); + System.out.println(doc1.getText(0, doc1.getLength())); + System.out.println(doc2.getText(0, doc2.getLength())); + System.out.println("ok"); + } + + private static void test() throws Exception { + doc1 = new PlainDocument(new StringContent()); + final UndoManager undoManager = new UndoManager(); + + doc1.addUndoableEditListener(undoManager); + doc1.insertString(0, "", null); + + doc2 = new PlainDocument(new StringContent()); + + doc2.addUndoableEditListener(undoManager); + doc2.insertString(0, "", null); + + Thread t1 = new Thread("Thread doc1") { + @Override + public void run() { + try { + barrier.await(); + for (int i = 0; i < 1000; i++) { + doc1.insertString(0, format1.format(i), null); + if(doc1.getLength() > 100) doc1.remove(0, 12); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + System.out.println("t1 done"); + } + }; + + Thread t2 = new Thread("Thread doc2") { + @Override + public void run() { + try { + barrier.await(); + for (int i = 0; i < 1000; i++) { + doc2.insertString(0, format2.format(i), null); + if(doc2.getLength() > 100) doc2.remove(0, 13); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + System.out.println("t2 done"); + } + }; + + Thread t3 = new Thread("Undo/Redo Thread") { + @Override + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + for (int i = 0; i < 1000; i++) { + undoManager.undoOrRedo(); + undoManager.undo(); + } + System.out.println("t3 done"); + } + }; + + t1.start(); + t2.start(); + t3.start(); + + t1.join(); + t2.join(); + t3.join(); + } +} From e300345cc8e854f9ad7fe5347d4fe07ec93cfc9c Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 2 Dec 2015 00:34:35 +0530 Subject: [PATCH 009/151] 8074967: [macosx] JPEGImageReader incorrectly identifies YCbCr JPEGs as RGB in standard metadata Reviewed-by: prr, psadhukhan --- .../imageio/plugins/jpeg/JPEGMetadata.java | 12 +-- .../jpeg/JpegMetadataColorSpaceTest.java | 69 ++++++++++++++++++ .../javax/imageio/plugins/jpeg/nomarkers.jpg | Bin 0 -> 548 bytes 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java create mode 100644 jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index f25863955ec..7975efda580 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -874,13 +874,13 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return chroma; } - boolean idsAreJFIF = true; + boolean idsAreJFIF = false; - for (int i = 0; i < sof.componentSpecs.length; i++) { - int id = sof.componentSpecs[i].componentId; - if ((id < 1) || (id >= sof.componentSpecs.length)) { - idsAreJFIF = false; - } + int cid0 = sof.componentSpecs[0].componentId; + int cid1 = sof.componentSpecs[1].componentId; + int cid2 = sof.componentSpecs[2].componentId; + if ((cid0 == 1) && (cid1 == 2) && (cid2 == 3)) { + idsAreJFIF = true; } if (idsAreJFIF) { diff --git a/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java b/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java new file mode 100644 index 00000000000..dbe54f553e2 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8074967 + * @summary Test verifies if there is no JFIF & EXIF header + * and sampling factor is same of JPEG image, then + * JPEG colorspace should not be RGB. + * @run main JpegMetadataColorSpaceTest + */ + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataFormatImpl; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.stream.ImageInputStream; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +public class JpegMetadataColorSpaceTest { + public static void main(String[] args) throws IOException { + String fileName = "nomarkers.jpg"; + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep+fileName; + System.out.println("Test file: " + filePath); + File file = new File(filePath); + ImageInputStream stream = ImageIO.createImageInputStream(file); + Iterator readers = ImageIO.getImageReaders(stream); + + if(readers.hasNext()) { + ImageReader reader = readers.next(); + reader.setInput(stream); + IIOMetadata metadata = reader.getImageMetadata(0); + + IIOMetadataNode standardTree = (IIOMetadataNode) + metadata.getAsTree + (IIOMetadataFormatImpl.standardMetadataFormatName); + IIOMetadataNode colorSpaceType = (IIOMetadataNode) + standardTree.getElementsByTagName("ColorSpaceType").item(0); + String colorSpaceName = colorSpaceType.getAttribute("name"); + if(colorSpaceName.equals("RGB")) + throw new RuntimeException("Identified incorrect ColorSpace"); + } + } +} diff --git a/jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg b/jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b08cdd3b02b159411cd54e30c2683be6d8ca6b0 GIT binary patch literal 548 zcmb79+YN#+6uq~lP-wvxTjbZoJs|PRE!@N%9K$h;L--h`wjq+BJmSgu>CJi7-Q5fJ zKnV%-h&&l*EQ(l`Br%tnlp+%%FG`gcx)4HDO0SKzR<1U6W$Myc6GD)BPsCEjQj?3^ z{0(;n&7p;sq6VUoYIHZSfCxiye>Oi?a8HmFfhei~@X`)V{p%Fm>O1r3-P~s)Bcavk saREhaa85va!DL0;bQO~VY_|CM3{XE@oe#TFE-Y0`OFO~L5HEPV0ZWiZasU7T literal 0 HcmV?d00001 From 3a2b32b7076804276dbe02c4f9d11ee20bcc981e Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 2 Dec 2015 00:47:36 +0530 Subject: [PATCH 010/151] 6967419: IndexOutOfBoundsException when drawing PNGs Reviewed-by: prr, psadhukhan --- .../imageio/plugins/png/PNGImageWriter.java | 12 ++- .../plugins/png/PngForceStopWritingTest.java | 76 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index 0004904aa99..278882e5385 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -193,7 +193,17 @@ final class IDATOutputStream extends ImageOutputStreamImpl { // Return to end of chunk and flush to minimize buffering stream.seek(pos); - stream.flushBefore(pos); + try { + stream.flushBefore(pos); + } catch (IOException e) { + /* + * If flushBefore() fails we try to access startPos in finally + * block of write_IDAT(). We should update startPos to avoid + * IndexOutOfBoundException while seek() is happening. + */ + this.startPos = stream.getStreamPosition(); + throw e; + } } public int read() throws IOException { diff --git a/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java b/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java new file mode 100644 index 00000000000..b2da248787c --- /dev/null +++ b/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6967419 + * @summary Test verifies that when we force stop PNG writing to + * ImageOutputStream, it should not cause IndexOutOfBoundException. + * @run main PngForceStopWritingTest + */ + +import java.awt.Color; +import java.awt.GradientPaint; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; + +public class PngForceStopWritingTest { + + public static void main(String[] args) throws IOException { + + OutputStream outputStream = new NullOutputStream(); + ImageOutputStream imageOutputStream = + ImageIO.createImageOutputStream(outputStream); + try { + ImageIO.write(createImage(2048),"PNG", imageOutputStream); + } catch (IOException e) { + imageOutputStream.close(); + } + } + + private static BufferedImage createImage(int size) { + + BufferedImage image = new + BufferedImage(size, size, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = image.createGraphics(); + g.setPaint(new GradientPaint(0, 0, Color.blue, size, size, Color.red)); + g.fillRect(0, 0, size, size); + g.dispose(); + return image; + } + + static class NullOutputStream extends OutputStream { + long count = 0; + @Override + public void write(int b) throws IOException { + count++; + if (count > 30000L) { + throw new IOException("Force stop image writing"); + } + } + } +} From 2b89c8529ddb210492786b533435521fa9eef559 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 2 Dec 2015 00:52:49 +0530 Subject: [PATCH 011/151] 8041501: ImageIO reader is not capable of reading JPEGs without JFIF header Reviewed-by: prr, psadhukhan --- .../share/native/libjavajpeg/imageioJPEG.c | 30 ++++---- .../plugins/jpeg/JpegImageColorSpaceTest.java | 69 +++++++++++++++++++ 2 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java diff --git a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c index f0d5c019a8d..81fe9117d04 100644 --- a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c +++ b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c @@ -1610,6 +1610,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader int ret; int h_samp0, h_samp1, h_samp2; int v_samp0, v_samp1, v_samp2; + int cid0, cid1, cid2; jboolean retval = JNI_FALSE; imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); j_decompress_ptr cinfo; @@ -1711,17 +1712,15 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader } } else if (!cinfo->saw_JFIF_marker && !IS_EXIF(cinfo)) { /* - * IJG assumes all unidentified 3-channels are YCbCr. - * We assume that only if the second two channels are - * subsampled (either horizontally or vertically). If not, - * we assume RGB. - * - * 4776576: Some digital cameras output YCbCr JPEG images - * that do not contain a JFIF APP0 marker but are only - * vertically subsampled (no horizontal subsampling). - * We should only assume this is RGB data if the subsampling - * factors for the second two channels are the same as the - * first (check both horizontal and vertical factors). + * In the absence of certain markers, IJG has interpreted + * component id's of [1,2,3] as meaning YCbCr.We follow that + * interpretation, which is additionally described in the Image + * I/O JPEG metadata spec.If that condition is not met here the + * next step will be to examine the subsampling factors, if + * there is any difference in subsampling factors we also assume + * YCbCr, only if both horizontal and vertical subsampling + * is same we assume JPEG color space as RGB. + * This is also described in the Image I/O JPEG metadata spec. */ h_samp0 = cinfo->comp_info[0].h_samp_factor; h_samp1 = cinfo->comp_info[1].h_samp_factor; @@ -1731,8 +1730,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader v_samp1 = cinfo->comp_info[1].v_samp_factor; v_samp2 = cinfo->comp_info[2].v_samp_factor; - if ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) && - (v_samp1 == v_samp0) && (v_samp2 == v_samp0)) + cid0 = cinfo->comp_info[0].component_id; + cid1 = cinfo->comp_info[1].component_id; + cid2 = cinfo->comp_info[2].component_id; + + if ((!(cid0 == 1 && cid1 == 2 && cid2 == 3)) && + ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) && + (v_samp1 == v_samp0) && (v_samp2 == v_samp0))) { cinfo->jpeg_color_space = JCS_RGB; /* output is already RGB, so it stays the same */ diff --git a/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java b/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java new file mode 100644 index 00000000000..c18b8216120 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8041501 + * @summary Test verifies if there is no JFIF & EXIF header + * and sampling factor is same of JPEG image, then + * imageIO should not override colorspace determined + * in IJG library. + * @run main JpegImageColorSpaceTest + */ + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class JpegImageColorSpaceTest { + + public static void main(String args[]) throws Exception { + + String fileName = "nomarkers.jpg"; + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep+fileName; + System.out.println("Test file: " + filePath); + File imageFile = new File(filePath); + + BufferedImage bufferedImage = ImageIO.read(imageFile); + int imageWidth = bufferedImage.getWidth(); + int imageHeight = bufferedImage.getHeight(); + + for (int i = 0; i < imageWidth; i++) { + for(int j = 0; j < imageHeight; j++) { + /* + * Since image is white we check individual pixel values from + * BufferedImage to verify if ImageIO.read() is done with proper + * color space or not. + */ + if (bufferedImage.getRGB(i, j) != Color.white.getRGB()) { + // color space is not proper + throw new RuntimeException("ColorSpace is not determined " + + "properly by ImageIO"); + } + } + } + } +} From 854c76518636eacf0496f971fc4fd75a7eed8e9f Mon Sep 17 00:00:00 2001 From: Jiri Vanek Date: Wed, 2 Dec 2015 21:23:59 +0000 Subject: [PATCH 012/151] 8144071: ImageIO does not reset stream if an exception is thrown Reset the I/O stream in a finally block Reviewed-by: andrew --- .../share/classes/javax/imageio/ImageIO.java | 9 +- .../imageio/spi/MarkTryFinallyReproducer.java | 367 ++++++++++++++++++ 2 files changed, 373 insertions(+), 3 deletions(-) create mode 100644 jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java index 7beea7b77a6..b56975ba15b 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -564,9 +564,12 @@ public final class ImageIO { if (stream != null) { stream.mark(); } - canDecode = spi.canDecodeInput(input); - if (stream != null) { - stream.reset(); + try { + canDecode = spi.canDecodeInput(input); + } finally { + if (stream != null) { + stream.reset(); + } } return canDecode; diff --git a/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java b/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java new file mode 100644 index 00000000000..7efd06a62f4 --- /dev/null +++ b/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java @@ -0,0 +1,367 @@ +/* + * Copyright 2015 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8144071 + * @run main/othervm MarkTryFinallyReproducer + * @summary Test that call to canDecodeInput in ImageIO don't corrupt + * mark/reset stack in ImageInputStream + * @author Jiri Vanek + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteOrder; +import java.util.Locale; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.IIOByteBuffer; +import javax.imageio.stream.ImageInputStream; + + +public class MarkTryFinallyReproducer { + + private static final byte[] bmp = new byte[]{ + 127,127, 66, 77, -86, 0, 0, 0, 0, 0, 0, 0, + 122, 0, 0, 0, 108, 0, 0, 0, 4, 0, 0, 0, 4, + 0, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 48, 0, 0, + 0, 19, 11, 0, 0, 19, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 66, 71, 82, 115, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1, -1, + -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, 0, 0, -17, + 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, -1, -1, + -1, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, -1 + }; + //first two are evil, we are skipping them later. Others are normal BMP + + private static class NotClosingImageInputStream implements ImageInputStream { + + private final ImageInputStream src; + + private NotClosingImageInputStream(ImageInputStream createImageInputStream) { + this.src = createImageInputStream; + } + + @Override + public void setByteOrder(ByteOrder byteOrder) { + src.setByteOrder(byteOrder); + } + + @Override + public ByteOrder getByteOrder() { + return src.getByteOrder(); + } + + @Override + public int read() throws IOException { + return src.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return src.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return src.read(b, off, len); + } + + @Override + public void readBytes(IIOByteBuffer buf, int len) throws IOException { + src.readBytes(buf, len); + } + + @Override + public boolean readBoolean() throws IOException { + return src.readBoolean(); + } + + @Override + public byte readByte() throws IOException { + return src.readByte(); + } + + @Override + public int readUnsignedByte() throws IOException { + return src.readUnsignedByte(); + } + + @Override + public short readShort() throws IOException { + return src.readShort(); + } + + @Override + public int readUnsignedShort() throws IOException { + return src.readUnsignedShort(); + } + + @Override + public char readChar() throws IOException { + return src.readChar(); + } + + @Override + public int readInt() throws IOException { + return src.readInt(); + } + + @Override + public long readUnsignedInt() throws IOException { + return src.readUnsignedInt(); + } + + @Override + public long readLong() throws IOException { + return src.readLong(); + } + + @Override + public float readFloat() throws IOException { + return src.readFloat(); + } + + @Override + public double readDouble() throws IOException { + return src.readDouble(); + } + + @Override + public String readLine() throws IOException { + return src.readLine(); + } + + @Override + public String readUTF() throws IOException { + return src.readUTF(); + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + src.readFully(b, off, len); + } + + @Override + public void readFully(byte[] b) throws IOException { + src.readFully(b); + } + + @Override + public void readFully(short[] s, int off, int len) throws IOException { + src.readFully(s, off, len); + } + + @Override + public void readFully(char[] c, int off, int len) throws IOException { + src.readFully(c, off, len); + } + + @Override + public void readFully(int[] i, int off, int len) throws IOException { + src.readFully(i, off, len); + } + + @Override + public void readFully(long[] l, int off, int len) throws IOException { + src.readFully(l, off, len); + } + + @Override + public void readFully(float[] f, int off, int len) throws IOException { + src.readFully(f, off, len); + } + + @Override + public void readFully(double[] d, int off, int len) throws IOException { + src.readFully(d, off, len); + } + + @Override + public long getStreamPosition() throws IOException { + return src.getStreamPosition(); + } + + @Override + public int getBitOffset() throws IOException { + return src.getBitOffset(); + } + + @Override + public void setBitOffset(int bitOffset) throws IOException { + src.setBitOffset(bitOffset); + } + + @Override + public int readBit() throws IOException { + return src.readBit(); + } + + @Override + public long readBits(int numBits) throws IOException { + return src.readBits(numBits); + } + + @Override + public long length() throws IOException { + return src.length(); + } + + @Override + public int skipBytes(int n) throws IOException { + return src.skipBytes(n); + } + + @Override + public long skipBytes(long n) throws IOException { + return src.skipBytes(n); + } + + @Override + public void seek(long pos) throws IOException { + src.seek(pos); + } + + @Override + public void mark() { + src.mark(); + } + + @Override + public void reset() throws IOException { + src.reset(); + } + + @Override + public void flushBefore(long pos) throws IOException { + src.flushBefore(pos); + } + + @Override + public void flush() throws IOException { + src.flush(); + } + + @Override + public long getFlushedPosition() { + return src.getFlushedPosition(); + } + + @Override + public boolean isCached() { + return src.isCached(); + } + + @Override + public boolean isCachedMemory() { + return src.isCachedMemory(); + } + + @Override + public boolean isCachedFile() { + return src.isCachedFile(); + } + + @Override + public void close() throws IOException { + //the only important one. nothing + } + } + + static final String readerClassName + = MarkTryFinallyReproducerSpi.class.getName(); + static final String[] localNames = {"myNames"}; + static final String[] localSuffixes = {"mySuffixes"}; + static final String[] localMIMETypes = {"myMimes"}; + + public static class MarkTryFinallyReproducerSpi extends ImageReaderSpi { + + public MarkTryFinallyReproducerSpi() { + super("MarkTryFinallyReproducerSpi", + "1.0", + localNames, + localSuffixes, + localMIMETypes, + readerClassName, + new Class[]{ImageInputStream.class}, + new String[0], + false, + null, + null, + new String[0], + new String[0], + false, + null, + null, + new String[0], + new String[0]); + } + + @Override + public String getDescription(Locale locale) { + return ""; + } + + @Override + public boolean canDecodeInput(Object input) throws IOException { + throw new IOException("Bad luck"); + } + + @Override + public ImageReader createReaderInstance(Object extension) { + return null; + } + } + + public static void main(String[] args) throws IOException { + MarkTryFinallyReproducerSpi spi = new MarkTryFinallyReproducerSpi(); + IIORegistry.getDefaultInstance().registerServiceProvider(spi); + + ImageInputStream iis1 = + new NotClosingImageInputStream(ImageIO.createImageInputStream(new ByteArrayInputStream(bmp))); + iis1.readByte(); + iis1.mark(); + long p1 = iis1.getStreamPosition(); + iis1.readByte(); + iis1.mark(); + long p2 = iis1.getStreamPosition(); + BufferedImage bi1 = ImageIO.read(iis1); + iis1.reset(); + long pn2 = iis1.getStreamPosition(); + iis1.reset(); + long pn1 = iis1.getStreamPosition(); + if (p1 != pn1 || p2!= pn2) { + throw new RuntimeException("Exception from call to canDecodeInput in ImageIO. " + + "Corrupted stack in ImageInputStream"); + } + + } + +} From 59accc606b6d79a8dba0a86d11fa92fa7e52cb23 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 3 Dec 2015 12:27:02 +0530 Subject: [PATCH 013/151] 8131754: AquaTreeUI.getCollapsedIcon() issue reported in java beans tests with a modular build Reviewed-by: malenkov, alexsch --- .../share/classes/javax/swing/JComponent.java | 1 + .../XMLEncoder/javax_swing_JComponent.java | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java index 3276d534a48..b6fa1b7bd81 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -618,6 +618,7 @@ public abstract class JComponent extends Container implements Serializable, * @return the {@code ComponentUI} object that renders this component * @since 1.9 */ + @Transient public ComponentUI getUI() { return ui; } diff --git a/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java b/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java new file mode 100644 index 00000000000..9ca11f9954a --- /dev/null +++ b/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +/* + * @test + * @bug 8131754 + * @summary Tests JComponent encoding + */ +public final class javax_swing_JComponent extends AbstractTest { + + public static void main(final String[] args) { + new javax_swing_JComponent().test(true); + } + + protected JComponent getObject() { + return new SimpleJComponent(); + } + + protected JComponent getAnotherObject() { + return new CustomJComponent(); + } + + public static final class SimpleJComponent extends JComponent { + + } + + public static final class CustomJComponent extends JComponent { + + public CustomJComponent() { + ui = new CustomUI(); + } + + @Override + public ComponentUI getUI() { + return ui; + } + + @Override + public void setUI(final ComponentUI newUI) { + ui = newUI; + } + } + + public static final class CustomUI extends ComponentUI { + + public boolean getFlag() { + throw new Error(); + } + + public void setFlag(final boolean flag) { + throw new Error(); + } + } +} From e469a43b3e5a9916af1be5630237a4d014c9c4b5 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 3 Dec 2015 12:00:37 +0100 Subject: [PATCH 014/151] 8141526: Allow to collect stdout/stderr from the FinalizationRunner even before the process returns Reviewed-by: dsamersoff --- .../share/classes/jdk/test/lib/Asserts.java | 620 +++++++++++++++++ .../classes/jdk/test/lib/JDKToolFinder.java | 106 +++ .../classes/jdk/test/lib/JDKToolLauncher.java | 135 ++++ .../share/classes/jdk/test/lib/Platform.java | 206 ++++++ .../lib/share/classes/jdk/test/lib/Utils.java | 640 ++++++++++++++++++ .../jdk/test/lib/process/OutputAnalyzer.java | 436 ++++++++++++ .../jdk/test/lib/process/OutputBuffer.java | 59 ++ .../jdk/test/lib/process/ProcessTools.java | 590 ++++++++++++++++ .../jdk/test/lib/process/StreamPumper.java | 197 ++++++ 9 files changed, 2989 insertions(+) create mode 100644 test/lib/share/classes/jdk/test/lib/Asserts.java create mode 100644 test/lib/share/classes/jdk/test/lib/JDKToolFinder.java create mode 100644 test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java create mode 100644 test/lib/share/classes/jdk/test/lib/Platform.java create mode 100644 test/lib/share/classes/jdk/test/lib/Utils.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/ProcessTools.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/StreamPumper.java diff --git a/test/lib/share/classes/jdk/test/lib/Asserts.java b/test/lib/share/classes/jdk/test/lib/Asserts.java new file mode 100644 index 00000000000..f0be92ef331 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/Asserts.java @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.util.Objects; + +/** + * Asserts that can be used for verifying assumptions in tests. + * + * An assertion will throw a {@link RuntimeException} if the assertion isn't true. + * All the asserts can be imported into a test by using a static import: + * + *
+ * {@code
+ * import static jdk.testlibrary.Asserts.*;
+ * }
+ *
+ * Always provide a message describing the assumption if the line number of the
+ * failing assertion isn't enough to understand why the assumption failed. For
+ * example, if the assertion is in a loop or in a method that is called
+ * multiple times, then the line number won't provide enough context to
+ * understand the failure.
+ * 
+ */ +public class Asserts { + + /** + * Shorthand for {@link #assertLessThan(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThan(Comparable, Comparable) + */ + public static > void assertLT(T lhs, T rhs) { + assertLessThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThan(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertLessThan(Comparable, Comparable, String) + */ + public static > void assertLT(T lhs, T rhs, String msg) { + assertLessThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThan(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThan(Comparable, Comparable, String) + */ + public static > void assertLessThan(T lhs, T rhs) { + assertLessThan(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is less than {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static >void assertLessThan(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) < 0)) { + msg = Objects.toString(msg, "assertLessThan") + + ": expected that " + Objects.toString(lhs) + + " < " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThanOrEqual(Comparable, Comparable) + */ + public static > void assertLTE(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertLessThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertLTE(T lhs, T rhs, String msg) { + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThanOrEqual(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertLessThanOrEqual(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is less than or equal to {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertLessThanOrEqual(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) <= 0)) { + msg = Objects.toString(msg, "assertLessThanOrEqual") + + ": expected that " + Objects.toString(lhs) + + " <= " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertEquals(Object, Object)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertEquals(Object, Object) + */ + public static void assertEQ(Object lhs, Object rhs) { + assertEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertEquals(Object, Object, String)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertEquals(Object, Object, String) + */ + public static void assertEQ(Object lhs, Object rhs, String msg) { + assertEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertEquals(java.lang.Object, java.lang.Object, java.lang.String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertEquals(Object, Object, String) + */ + public static void assertEquals(Object lhs, Object rhs) { + assertEquals(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertEquals(Object lhs, Object rhs, String msg) { + if ((lhs != rhs) && ((lhs == null) || !(lhs.equals(rhs)))) { + msg = Objects.toString(msg, "assertEquals") + + ": expected " + Objects.toString(lhs) + + " to equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Calls {@link #assertSame(java.lang.Object, java.lang.Object, java.lang.String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertSame(Object, Object, String) + */ + public static void assertSame(Object lhs, Object rhs) { + assertSame(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is the same as {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertSame(Object lhs, Object rhs, String msg) { + if (lhs != rhs) { + msg = Objects.toString(msg, "assertSame") + + ": expected " + Objects.toString(lhs) + + " to equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThanOrEqual(Comparable, Comparable) + */ + public static > void assertGTE(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertGreaterThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertGTE(T lhs, T rhs, String msg) { + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is greater than or equal to {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) >= 0)) { + msg = Objects.toString(msg, "assertGreaterThanOrEqual") + + ": expected " + Objects.toString(lhs) + + " >= " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThan(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThan(Comparable, Comparable) + */ + public static > void assertGT(T lhs, T rhs) { + assertGreaterThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThan(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs the left hand value + * @param rhs the right hand value + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertGreaterThan(Comparable, Comparable, String) + */ + public static > void assertGT(T lhs, T rhs, String msg) { + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThan(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs the left hand value + * @param rhs the right hand value + * @see #assertGreaterThan(Comparable, Comparable, String) + */ + public static > void assertGreaterThan(T lhs, T rhs) { + assertGreaterThan(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is greater than {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertGreaterThan(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) > 0)) { + msg = Objects.toString(msg, "assertGreaterThan") + + ": expected " + Objects.toString(lhs) + + " > " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertNotEquals(Object, Object)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertNotEquals(Object, Object) + */ + public static void assertNE(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertNotEquals(Object, Object, String)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertNotEquals(Object, Object, String) + */ + public static void assertNE(Object lhs, Object rhs, String msg) { + assertNotEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertNotEquals(Object, Object, String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertNotEquals(Object, Object, String) + */ + public static void assertNotEquals(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is not equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNotEquals(Object lhs, Object rhs, String msg) { + if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) { + msg = Objects.toString(msg, "assertNotEquals") + + ": expected " + Objects.toString(lhs) + + " to not equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Calls {@link #assertNull(Object, String)} with a default message. + * + * @param o The reference assumed to be null. + * @see #assertNull(Object, String) + */ + public static void assertNull(Object o) { + assertNull(o, null); + } + + /** + * Asserts that {@code o} is null. + * + * @param o The reference assumed to be null. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNull(Object o, String msg) { + assertEquals(o, null, msg); + } + + /** + * Calls {@link #assertNotNull(Object, String)} with a default message. + * + * @param o The reference assumed not to be null, + * @see #assertNotNull(Object, String) + */ + public static void assertNotNull(Object o) { + assertNotNull(o, null); + } + + /** + * Asserts that {@code o} is not null. + * + * @param o The reference assumed not to be null, + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNotNull(Object o, String msg) { + assertNotEquals(o, null, msg); + } + + /** + * Calls {@link #assertFalse(boolean, String)} with a default message. + * + * @param value The value assumed to be false. + * @see #assertFalse(boolean, String) + */ + public static void assertFalse(boolean value) { + assertFalse(value, null); + } + + /** + * Asserts that {@code value} is {@code false}. + * + * @param value The value assumed to be false. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertFalse(boolean value, String msg) { + if (value) { + msg = Objects.toString(msg, "assertFalse") + + ": expected false, was true"; + fail(msg); + } + } + + /** + * Calls {@link #assertTrue(boolean, String)} with a default message. + * + * @param value The value assumed to be true. + * @see #assertTrue(boolean, String) + */ + public static void assertTrue(boolean value) { + assertTrue(value, null); + } + + /** + * Asserts that {@code value} is {@code true}. + * + * @param value The value assumed to be true. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertTrue(boolean value, String msg) { + if (!value) { + msg = Objects.toString(msg, "assertTrue") + + ": expected true, was false"; + fail(msg); + } + } + + private static > int compare(T lhs, T rhs, String msg) { + if (lhs == null || rhs == null) { + fail(lhs, rhs, msg + ": values must be non-null:", ","); + } + return lhs.compareTo(rhs); + } + +/** + * Asserts that two strings are equal. + * + * If strings are not equals, then exception message + * will contain {@code msg} followed by list of mismatched lines. + * + * @param str1 First string to compare. + * @param str2 Second string to compare. + * @param msg A description of the assumption. + * @throws RuntimeException if strings are not equal. + */ + public static void assertStringsEqual(String str1, String str2, + String msg) { + String lineSeparator = System.getProperty("line.separator"); + String str1Lines[] = str1.split(lineSeparator); + String str2Lines[] = str2.split(lineSeparator); + + int minLength = Math.min(str1Lines.length, str2Lines.length); + String longestStringLines[] = ((str1Lines.length == minLength) ? + str2Lines : str1Lines); + + boolean stringsAreDifferent = false; + + StringBuilder messageBuilder = new StringBuilder(msg); + + messageBuilder.append("\n"); + + for (int line = 0; line < minLength; line++) { + if (!str1Lines[line].equals(str2Lines[line])) { + messageBuilder.append(String. + format("[line %d] '%s' differs " + + "from '%s'\n", + line, + str1Lines[line], + str2Lines[line])); + stringsAreDifferent = true; + } + } + + if (minLength < longestStringLines.length) { + String stringName = ((longestStringLines == str1Lines) ? + "first" : "second"); + messageBuilder.append(String.format("Only %s string contains " + + "following lines:\n", + stringName)); + stringsAreDifferent = true; + for(int line = minLength; line < longestStringLines.length; line++) { + messageBuilder.append(String. + format("[line %d] '%s'", line, + longestStringLines[line])); + } + } + + if (stringsAreDifferent) { + fail(messageBuilder.toString()); + } + } + + /** + * Returns a string formatted with a message and expected and actual values. + * @param lhs the actual value + * @param rhs the expected value + * @param message the actual value + * @param relation the asserted relationship between lhs and rhs + * @return a formatted string + */ + public static String format(Object lhs, Object rhs, String message, String relation) { + StringBuilder sb = new StringBuilder(80); + if (message != null) { + sb.append(message); + sb.append(' '); + } + sb.append("<"); + sb.append(Objects.toString(lhs)); + sb.append("> "); + sb.append(Objects.toString(relation, ",")); + sb.append(" <"); + sb.append(Objects.toString(rhs)); + sb.append(">"); + return sb.toString(); + } + + /** + * Fail reports a failure with message fail. + * + * @throws RuntimeException always + */ + public static void fail() { + fail("fail"); + } + + /** + * Fail reports a failure with a message. + * @param message for the failure + * @throws RuntimeException always + */ + public static void fail(String message) { + throw new RuntimeException(message); + } + + /** + * Fail reports a failure with a formatted message. + * + * @param lhs the actual value + * @param rhs the expected value + * @param message to be format before the expected and actual values + * @param relation the asserted relationship between lhs and rhs + * @throws RuntimeException always + */ + public static void fail(Object lhs, Object rhs, String message, String relation) { + throw new RuntimeException(format(lhs, rhs, message, relation)); + } + + /** + * Fail reports a failure with a message and a cause. + * @param message to be format before the expected and actual values + * @param cause the exception that caused this failure + * @throws RuntimeException always + */ + public static void fail(String message, Throwable cause) { + throw new RuntimeException(message, cause); + } + +} diff --git a/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java b/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java new file mode 100644 index 00000000000..3ad008e0005 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.io.FileNotFoundException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class JDKToolFinder { + + private JDKToolFinder() { + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code test.jdk} or {@code compile.jdk} (both are set by the jtreg test suite) + * + * @return Full path to an executable in jdk/bin + */ + public static String getJDKTool(String tool) { + + // First try to find the executable in test.jdk + try { + return getTool(tool, "test.jdk"); + } catch (FileNotFoundException e) { + + } + + // Now see if it's available in compile.jdk + try { + return getTool(tool, "compile.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException("Failed to find " + tool + + ", looked in test.jdk (" + System.getProperty("test.jdk") + + ") and compile.jdk (" + System.getProperty("compile.jdk") + ")"); + } + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code compile.jdk} + * + * @return Full path to an executable in jdk/bin + */ + public static String getCompileJDKTool(String tool) { + try { + return getTool(tool, "compile.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code test.jdk} + * + * @return Full path to an executable in jdk/bin + */ + public static String getTestJDKTool(String tool) { + try { + return getTool(tool, "test.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static String getTool(String tool, String property) throws FileNotFoundException { + String jdkPath = System.getProperty(property); + + if (jdkPath == null) { + throw new RuntimeException( + "System property '" + property + "' not set. This property is normally set by jtreg. " + + "When running test separately, set this property using '-D" + property + "=/path/to/jdk'."); + } + + Path toolName = Paths.get("bin", tool + (Platform.isWindows() ? ".exe" : "")); + + Path jdkTool = Paths.get(jdkPath, toolName.toString()); + if (!jdkTool.toFile().exists()) { + throw new FileNotFoundException("Could not find file " + jdkTool.toAbsolutePath()); + } + + return jdkTool.toAbsolutePath().toString(); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java b/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java new file mode 100644 index 00000000000..3948d474ec1 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.test.lib.process.*; + +/** + * A utility for constructing command lines for starting JDK tool processes. + * + * The JDKToolLauncher can in particular be combined with a + * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following + * code run {@code jmap -heap} against a process with GC logging turned on for + * the {@code jmap} process: + * + *
+ * {@code
+ * JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
+ *                                       .addVMArg("-XX:+PrintGC");
+ *                                       .addVMArg("-XX:+PrintGCDetails")
+ *                                       .addToolArg("-heap")
+ *                                       .addToolArg(pid);
+ * ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
+ * Process p = pb.start();
+ * }
+ * 
+ */ +public class JDKToolLauncher { + private final String executable; + private final List vmArgs = new ArrayList(); + private final List toolArgs = new ArrayList(); + + private JDKToolLauncher(String tool, boolean useCompilerJDK) { + if (useCompilerJDK) { + executable = JDKToolFinder.getJDKTool(tool); + } else { + executable = JDKToolFinder.getTestJDKTool(tool); + } + vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs())); + } + + /** + * Creates a new JDKToolLauncher for the specified tool. Using tools path + * from the compiler JDK. + * + * @param tool + * The name of the tool + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher create(String tool) { + return new JDKToolLauncher(tool, true); + } + + /** + * Creates a new JDKToolLauncher for the specified tool in the Tested JDK. + * + * @param tool + * The name of the tool + * + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher createUsingTestJDK(String tool) { + return new JDKToolLauncher(tool, false); + } + + /** + * Adds an argument to the JVM running the tool. + * + * The JVM arguments are passed to the underlying JVM running the tool. + * Arguments will automatically be prepended with "-J". + * + * Any platform specific arguments required for running the tool are + * automatically added. + * + * + * @param arg + * The argument to VM running the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addVMArg(String arg) { + vmArgs.add(arg); + return this; + } + + /** + * Adds an argument to the tool. + * + * @param arg + * The argument to the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addToolArg(String arg) { + toolArgs.add(arg); + return this; + } + + /** + * Returns the command that can be used for running the tool. + * + * @return An array whose elements are the arguments of the command. + */ + public String[] getCommand() { + List command = new ArrayList(); + command.add(executable); + // Add -J in front of all vmArgs + for (String arg : vmArgs) { + command.add("-J" + arg); + } + command.addAll(toolArgs); + return command.toArray(new String[command.size()]); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/Platform.java b/test/lib/share/classes/jdk/test/lib/Platform.java new file mode 100644 index 00000000000..f809d694312 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/Platform.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.util.regex.Pattern; + +public class Platform { + private static final String osName = System.getProperty("os.name"); + private static final String dataModel = System.getProperty("sun.arch.data.model"); + private static final String vmVersion = System.getProperty("java.vm.version"); + private static final String javaVersion = System.getProperty("java.version"); + private static final String osArch = System.getProperty("os.arch"); + private static final String vmName = System.getProperty("java.vm.name"); + private static final String userName = System.getProperty("user.name"); + private static final String compiler = System.getProperty("sun.management.compiler"); + + public static boolean isClient() { + return vmName.endsWith(" Client VM"); + } + + public static boolean isServer() { + return vmName.endsWith(" Server VM"); + } + + public static boolean isGraal() { + return vmName.endsWith(" Graal VM"); + } + + public static boolean isZero() { + return vmName.endsWith(" Zero VM"); + } + + public static boolean isMinimal() { + return vmName.endsWith(" Minimal VM"); + } + + public static boolean isEmbedded() { + return vmName.contains("Embedded"); + } + + public static boolean isTieredSupported() { + return compiler.contains("Tiered Compilers"); + } + + public static boolean is32bit() { + return dataModel.equals("32"); + } + + public static boolean is64bit() { + return dataModel.equals("64"); + } + + public static boolean isAix() { + return isOs("aix"); + } + + public static boolean isLinux() { + return isOs("linux"); + } + + public static boolean isOSX() { + return isOs("mac"); + } + + public static boolean isSolaris() { + return isOs("sunos"); + } + + public static boolean isWindows() { + return isOs("win"); + } + + private static boolean isOs(String osname) { + return osName.toLowerCase().startsWith(osname.toLowerCase()); + } + + public static String getOsName() { + return osName; + } + + public static boolean isDebugBuild() { + return (vmVersion.toLowerCase().contains("debug") || + javaVersion.toLowerCase().contains("debug")); + } + + public static String getVMVersion() { + return vmVersion; + } + + // Returns true for sparc and sparcv9. + public static boolean isSparc() { + return isArch("sparc.*"); + } + + public static boolean isARM() { + return isArch("arm.*"); + } + + public static boolean isPPC() { + return isArch("ppc.*"); + } + + public static boolean isX86() { + // On Linux it's 'i386', Windows 'x86' without '_64' suffix. + return isArch("(i386)|(x86(?!_64))"); + } + + public static boolean isX64() { + // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64' + return isArch("(amd64)|(x86_64)"); + } + + public static boolean isAArch64() { + return isArch("aarch64"); + } + + private static boolean isArch(String archnameRE) { + return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE) + .matcher(osArch) + .matches(); + } + + public static String getOsArch() { + return osArch; + } + + /** + * Return a boolean for whether we expect to be able to attach + * the SA to our own processes on this system. + */ + public static boolean shouldSAAttach() throws Exception { + + if (isAix()) { + return false; // SA not implemented. + } else if (isLinux()) { + return canPtraceAttachLinux(); + } else if (isOSX()) { + return canAttachOSX(); + } else { + // Other platforms expected to work: + return true; + } + } + + /** + * On Linux, first check the SELinux boolean "deny_ptrace" and return false + * as we expect to be denied if that is "1". Then expect permission to attach + * if we are root, so return true. Then return false for an expected denial + * if "ptrace_scope" is 1, and true otherwise. + */ + public static boolean canPtraceAttachLinux() throws Exception { + + // SELinux deny_ptrace: + String deny_ptrace = Utils.fileAsString("/sys/fs/selinux/booleans/deny_ptrace"); + if (deny_ptrace != null && deny_ptrace.contains("1")) { + // ptrace will be denied: + return false; + } + + // YAMA enhanced security ptrace_scope: + // 0 - a process can PTRACE_ATTACH to any other process running under the same uid + // 1 - restricted ptrace: a process must be a children of the inferior or user is root + // 2 - only processes with CAP_SYS_PTRACE may use ptrace or user is root + // 3 - no attach: no processes may use ptrace with PTRACE_ATTACH + String ptrace_scope = Utils.fileAsString("/proc/sys/kernel/yama/ptrace_scope"); + if (ptrace_scope != null) { + if (ptrace_scope.startsWith("3")) { + return false; + } + if (!userName.equals("root") && !ptrace_scope.startsWith("0")) { + // ptrace will be denied: + return false; + } + } + // Otherwise expect to be permitted: + return true; + } + + /** + * On OSX, expect permission to attach only if we are root. + */ + public static boolean canAttachOSX() throws Exception { + return userName.equals("root"); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/Utils.java b/test/lib/share/classes/jdk/test/lib/Utils.java new file mode 100644 index 00000000000..5634e088074 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/Utils.java @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.ServerSocket; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.function.BooleanSupplier; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.misc.Unsafe; + +import jdk.test.lib.process.*; +import static jdk.test.lib.Asserts.assertTrue; + +/** + * Common library for various test helper functions. + */ +public final class Utils { + + /** + * Returns the value of 'test.class.path' system property. + */ + public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", "."); + + /** + * Returns the sequence used by operating system to separate lines. + */ + public static final String NEW_LINE = System.getProperty("line.separator"); + + /** + * Returns the value of 'test.vm.opts' system property. + */ + public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); + + /** + * Returns the value of 'test.java.opts' system property. + */ + public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + + /** + * Returns the value of 'test.src' system property. + */ + public static final String TEST_SRC = System.getProperty("test.src", "").trim(); + + private static Unsafe unsafe = null; + + /** + * Defines property name for seed value. + */ + public static final String SEED_PROPERTY_NAME = "jdk.test.lib.random.seed"; + + /* (non-javadoc) + * Random generator with (or without) predefined seed. Depends on + * "jdk.test.lib.random.seed" property value. + */ + private static volatile Random RANDOM_GENERATOR; + + /** + * Contains the seed value used for {@link java.util.Random} creation. + */ + public static final long SEED = Long.getLong(SEED_PROPERTY_NAME, new Random().nextLong()); + /** + * Returns the value of 'test.timeout.factor' system property + * converted to {@code double}. + */ + public static final double TIMEOUT_FACTOR; + static { + String toFactor = System.getProperty("test.timeout.factor", "1.0"); + TIMEOUT_FACTOR = Double.parseDouble(toFactor); + } + + /** + * Returns the value of JTREG default test timeout in milliseconds + * converted to {@code long}. + */ + public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120); + + private Utils() { + // Private constructor to prevent class instantiation + } + + /** + * Returns the list of VM options. + * + * @return List of VM options + */ + public static List getVmOptions() { + return Arrays.asList(safeSplitString(VM_OPTIONS)); + } + + /** + * Returns the list of VM options with -J prefix. + * + * @return The list of VM options with -J prefix + */ + public static List getForwardVmOptions() { + String[] opts = safeSplitString(VM_OPTIONS); + for (int i = 0; i < opts.length; i++) { + opts[i] = "-J" + opts[i]; + } + return Arrays.asList(opts); + } + + /** + * Returns the default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @return An array of options, or an empty array if no options. + */ + public static String[] getTestJavaOpts() { + List opts = new ArrayList(); + Collections.addAll(opts, safeSplitString(VM_OPTIONS)); + Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); + return opts.toArray(new String[0]); + } + + /** + * Combines given arguments with default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts + * @return The combination of JTReg test java options and user args. + */ + public static String[] addTestJavaOpts(String... userArgs) { + List opts = new ArrayList(); + Collections.addAll(opts, getTestJavaOpts()); + Collections.addAll(opts, userArgs); + return opts.toArray(new String[0]); + } + + /** + * Removes any options specifying which GC to use, for example "-XX:+UseG1GC". + * Removes any options matching: -XX:(+/-)Use*GC + * Used when a test need to set its own GC version. Then any + * GC specified by the framework must first be removed. + * @return A copy of given opts with all GC options removed. + */ + private static final Pattern useGcPattern = Pattern.compile( + "(?:\\-XX\\:[\\+\\-]Use.+GC)" + + "|(?:\\-Xconcgc)"); + public static List removeGcOpts(List opts) { + List optsWithoutGC = new ArrayList(); + for (String opt : opts) { + if (useGcPattern.matcher(opt).matches()) { + System.out.println("removeGcOpts: removed " + opt); + } else { + optsWithoutGC.add(opt); + } + } + return optsWithoutGC; + } + + /** + * Returns the default JTReg arguments for a jvm running a test without + * options that matches regular expressions in {@code filters}. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @param filters Regular expressions used to filter out options. + * @return An array of options, or an empty array if no options. + */ + public static String[] getFilteredTestJavaOpts(String... filters) { + String options[] = getTestJavaOpts(); + + if (filters.length == 0) { + return options; + } + + List filteredOptions = new ArrayList(options.length); + Pattern patterns[] = new Pattern[filters.length]; + for (int i = 0; i < filters.length; i++) { + patterns[i] = Pattern.compile(filters[i]); + } + + for (String option : options) { + boolean matched = false; + for (int i = 0; i < patterns.length && !matched; i++) { + Matcher matcher = patterns[i].matcher(option); + matched = matcher.find(); + } + if (!matched) { + filteredOptions.add(option); + } + } + + return filteredOptions.toArray(new String[filteredOptions.size()]); + } + + /** + * Splits a string by white space. + * Works like String.split(), but returns an empty array + * if the string is null or empty. + */ + private static String[] safeSplitString(String s) { + if (s == null || s.trim().isEmpty()) { + return new String[] {}; + } + return s.trim().split("\\s+"); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString(); + } + + /** + * Returns the free port on the local host. + * The function will spin until a valid port number is found. + * + * @return The port number + * @throws InterruptedException if any thread has interrupted the current thread + * @throws IOException if an I/O error occurs when opening the socket + */ + public static int getFreePort() throws InterruptedException, IOException { + int port = -1; + + while (port <= 0) { + Thread.sleep(100); + + ServerSocket serverSocket = null; + try { + serverSocket = new ServerSocket(0); + port = serverSocket.getLocalPort(); + } finally { + serverSocket.close(); + } + } + + return port; + } + + /** + * Returns the name of the local host. + * + * @return The host name + * @throws UnknownHostException if IP address of a host could not be determined + */ + public static String getHostname() throws UnknownHostException { + InetAddress inetAddress = InetAddress.getLocalHost(); + String hostName = inetAddress.getHostName(); + + assertTrue((hostName != null && !hostName.isEmpty()), + "Cannot get hostname"); + + return hostName; + } + + /** + * Uses "jcmd -l" to search for a jvm pid. This function will wait + * forever (until jtreg timeout) for the pid to be found. + * @param key Regular expression to search for + * @return The found pid. + */ + public static int waitForJvmPid(String key) throws Throwable { + final long iterationSleepMillis = 250; + System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); + System.out.flush(); + while (true) { + int pid = tryFindJvmPid(key); + if (pid >= 0) { + return pid; + } + Thread.sleep(iterationSleepMillis); + } + } + + /** + * Searches for a jvm pid in the output from "jcmd -l". + * + * Example output from jcmd is: + * 12498 sun.tools.jcmd.JCmd -l + * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar + * + * @param key A regular expression to search for. + * @return The found pid, or -1 if not found. + * @throws Exception If multiple matching jvms are found. + */ + public static int tryFindJvmPid(String key) throws Throwable { + OutputAnalyzer output = null; + try { + JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); + jcmdLauncher.addToolArg("-l"); + output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); + output.shouldHaveExitValue(0); + + // Search for a line starting with numbers (pid), follwed by the key. + Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); + Matcher matcher = pattern.matcher(output.getStdout()); + + int pid = -1; + if (matcher.find()) { + pid = Integer.parseInt(matcher.group(1)); + System.out.println("findJvmPid.pid: " + pid); + if (matcher.find()) { + throw new Exception("Found multiple JVM pids for key: " + key); + } + } + return pid; + } catch (Throwable t) { + System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); + throw t; + } + } + + /** + * Adjusts the provided timeout value for the TIMEOUT_FACTOR + * @param tOut the timeout value to be adjusted + * @return The timeout value adjusted for the value of "test.timeout.factor" + * system property + */ + public static long adjustTimeout(long tOut) { + return Math.round(tOut * Utils.TIMEOUT_FACTOR); + } + + /** + * Return the contents of the named file as a single String, + * or null if not found. + * @param filename name of the file to read + * @return String contents of file, or null if file not found. + * @throws IOException + * if an I/O error occurs reading from the file or a malformed or + * unmappable byte sequence is read + */ + public static String fileAsString(String filename) throws IOException { + Path filePath = Paths.get(filename); + if (!Files.exists(filePath)) return null; + return new String(Files.readAllBytes(filePath)); + } + + /** + * @return Unsafe instance. + */ + public static synchronized Unsafe getUnsafe() { + if (unsafe == null) { + try { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe) f.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + return unsafe; + } + private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + /** + * Returns hex view of byte array + * + * @param bytes byte array to process + * @return Space separated hexadecimal string representation of bytes + */ + + public static String toHexString(byte[] bytes) { + char[] hexView = new char[bytes.length * 3]; + int i = 0; + for (byte b : bytes) { + hexView[i++] = hexArray[(b >> 4) & 0x0F]; + hexView[i++] = hexArray[b & 0x0F]; + hexView[i++] = ' '; + } + return new String(hexView); + } + + /** + * Returns {@link java.util.Random} generator initialized with particular seed. + * The seed could be provided via system property {@link Utils#SEED_PROPERTY_NAME} + * In case no seed is provided, the method uses a random number. + * The used seed printed to stdout. + * @return {@link java.util.Random} generator with particular seed. + */ + public static Random getRandomInstance() { + if (RANDOM_GENERATOR == null) { + synchronized (Utils.class) { + if (RANDOM_GENERATOR == null) { + RANDOM_GENERATOR = new Random(SEED); + System.out.printf("For random generator using seed: %d%n", SEED); + System.out.printf("To re-run test with same seed value please add \"-D%s=%d\" to command line.%n", SEED_PROPERTY_NAME, SEED); + } + } + } + return RANDOM_GENERATOR; + } + + /** + * Returns random element of non empty collection + * + * @param a type of collection element + * @param collection collection of elements + * @return random element of collection + * @throws IllegalArgumentException if collection is empty + */ + public static T getRandomElement(Collection collection) + throws IllegalArgumentException { + if (collection.isEmpty()) { + throw new IllegalArgumentException("Empty collection"); + } + Random random = getRandomInstance(); + int elementIndex = 1 + random.nextInt(collection.size() - 1); + Iterator iterator = collection.iterator(); + while (--elementIndex != 0) { + iterator.next(); + } + return iterator.next(); + } + + /** + * Wait for condition to be true + * + * @param condition, a condition to wait for + */ + public static final void waitForCondition(BooleanSupplier condition) { + waitForCondition(condition, -1L, 100L); + } + + /** + * Wait until timeout for condition to be true + * + * @param condition, a condition to wait for + * @param timeout a time in milliseconds to wait for condition to be true + * specifying -1 will wait forever + * @return condition value, to determine if wait was successful + */ + public static final boolean waitForCondition(BooleanSupplier condition, + long timeout) { + return waitForCondition(condition, timeout, 100L); + } + + /** + * Wait until timeout for condition to be true for specified time + * + * @param condition, a condition to wait for + * @param timeout a time in milliseconds to wait for condition to be true, + * specifying -1 will wait forever + * @param sleepTime a time to sleep value in milliseconds + * @return condition value, to determine if wait was successful + */ + public static final boolean waitForCondition(BooleanSupplier condition, + long timeout, long sleepTime) { + long startTime = System.currentTimeMillis(); + while (!(condition.getAsBoolean() || (timeout != -1L + && ((System.currentTimeMillis() - startTime) > timeout)))) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new Error(e); + } + } + return condition.getAsBoolean(); + } + + /** + * Interface same as java.lang.Runnable but with + * method {@code run()} able to throw any Throwable. + */ + public static interface ThrowingRunnable { + void run() throws Throwable; + } + + /** + * Filters out an exception that may be thrown by the given + * test according to the given filter. + * + * @param test - method that is invoked and checked for exception. + * @param filter - function that checks if the thrown exception matches + * criteria given in the filter's implementation. + * @return - exception that matches the filter if it has been thrown or + * {@code null} otherwise. + * @throws Throwable - if test has thrown an exception that does not + * match the filter. + */ + public static Throwable filterException(ThrowingRunnable test, + Function filter) throws Throwable { + try { + test.run(); + } catch (Throwable t) { + if (filter.apply(t)) { + return t; + } else { + throw t; + } + } + return null; + } + + /** + * Ensures a requested class is loaded + * @param aClass class to load + */ + public static void ensureClassIsLoaded(Class aClass) { + if (aClass == null) { + throw new Error("Requested null class"); + } + try { + Class.forName(aClass.getName(), /* initialize = */ true, + ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error("Class not found", e); + } + } + /** + * @param parent a class loader to be the parent for the returned one + * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg + * property and with the given parent + */ + public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) { + URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator)) + .map(Paths::get) + .map(Path::toUri) + .map(x -> { + try { + return x.toURL(); + } catch (MalformedURLException ex) { + throw new Error("Test issue. JTREG property" + + " 'test.class.path'" + + " is not defined correctly", ex); + } + }).toArray(URL[]::new); + return new URLClassLoader(urls, parent); + } + + /** + * Runs runnable and checks that it throws expected exception. If exceptionException is null it means + * that we expect no exception to be thrown. + * @param runnable what we run + * @param expectedException expected exception + */ + public static void runAndCheckException(Runnable runnable, Class expectedException) { + runAndCheckException(runnable, t -> { + if (t == null) { + if (expectedException != null) { + throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); + } + } else { + String message = "Got unexpected exception " + t.getClass().getSimpleName(); + if (expectedException == null) { + throw new AssertionError(message, t); + } else if (!expectedException.isAssignableFrom(t.getClass())) { + message += " instead of " + expectedException.getSimpleName(); + throw new AssertionError(message, t); + } + } + }); + } + + /** + * Runs runnable and makes some checks to ensure that it throws expected exception. + * @param runnable what we run + * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise + */ + public static void runAndCheckException(Runnable runnable, Consumer checkException) { + try { + runnable.run(); + checkException.accept(null); + } catch (Throwable t) { + checkException.accept(t); + } + } + + /** + * Converts to VM type signature + * + * @param type Java type to convert + * @return string representation of VM type + */ + public static String toJVMTypeSignature(Class type) { + if (type.isPrimitive()) { + if (type == boolean.class) { + return "Z"; + } else if (type == byte.class) { + return "B"; + } else if (type == char.class) { + return "C"; + } else if (type == double.class) { + return "D"; + } else if (type == float.class) { + return "F"; + } else if (type == int.class) { + return "I"; + } else if (type == long.class) { + return "J"; + } else if (type == short.class) { + return "S"; + } else if (type == void.class) { + return "V"; + } else { + throw new Error("Unsupported type: " + type); + } + } + String result = type.getName().replaceAll("\\.", "/"); + if (!type.isArray()) { + return "L" + result + ";"; + } + return result; + } +} + diff --git a/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java new file mode 100644 index 00000000000..fc3a4de2905 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.process; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class OutputAnalyzer { + + private final String stdout; + private final String stderr; + private final int exitValue; + + /** + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process + * + * @param process Process to analyze + * @throws IOException If an I/O error occurs. + */ + public OutputAnalyzer(Process process) throws IOException { + OutputBuffer output = ProcessTools.getOutput(process); + exitValue = process.exitValue(); + this.stdout = output.getStdout(); + this.stderr = output.getStderr(); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param buf String buffer to analyze + */ + public OutputAnalyzer(String buf) { + this(buf, buf); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout stdout buffer to analyze + * @param stderr stderr buffer to analyze + */ + public OutputAnalyzer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; + } + + /** + * Verify that the stdout contents of output buffer is empty + * + * @throws RuntimeException + * If stdout was not empty + */ + public void stdoutShouldBeEmpty() { + if (!getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was not empty"); + } + } + + /** + * Verify that the stderr contents of output buffer is empty + * + * @throws RuntimeException + * If stderr was not empty + */ + public void stderrShouldBeEmpty() { + if (!getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } + } + + /** + * Verify that the stdout contents of output buffer is not empty + * + * @throws RuntimeException + * If stdout was empty + */ + public void stdoutShouldNotBeEmpty() { + if (getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was empty"); + } + } + + /** + * Verify that the stderr contents of output buffer is not empty + * + * @throws RuntimeException + * If stderr was empty + */ + public void stderrShouldNotBeEmpty() { + if (getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was empty"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer shouldContain(String expectedString) { + if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer stdoutShouldContain(String expectedString) { + if (!stdout.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer stderrShouldContain(String expectedString) { + if (!stderr.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer shouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + } + if (stderr.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { + if (stderr.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer matches + * the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer shouldMatch(String pattern) { + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!stdoutMatcher.find() && !stderrMatcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stdoutShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stderrShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * match the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer shouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stdout: '" + matcher.group() + "' \n"); + } + matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stderr: '" + matcher.group() + "' \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer stdoutShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer stderrShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stderr \n"); + } + return this; + } + + /** + * Get the captured group of the first string matching the pattern. + * stderr is searched before stdout. + * + * @param pattern The multi-line pattern to match + * @param group The group to capture + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern, int group) { + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (stderrMatcher.find()) { + return stderrMatcher.group(group); + } + if (stdoutMatcher.find()) { + return stdoutMatcher.group(group); + } + return null; + } + + /** + * Get the first string matching the pattern. + * stderr is searched before stdout. + * + * @param pattern The multi-line pattern to match + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern) { + return firstMatch(pattern, 0); + } + + /** + * Verify the exit value of the process + * + * @param expectedExitValue Expected exit value from process + * @throws RuntimeException If the exit value from the process did not match the expected value + */ + public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { + if (getExitValue() != expectedExitValue) { + reportDiagnosticSummary(); + throw new RuntimeException("Expected to get exit value of [" + + expectedExitValue + "]\n"); + } + return this; + } + + + /** + * Report summary that will help to diagnose the problem + * Currently includes: + * - standard input produced by the process under test + * - standard output + * - exit code + * Note: the command line is printed by the ProcessTools + */ + private void reportDiagnosticSummary() { + String msg = + " stdout: [" + stdout + "];\n" + + " stderr: [" + stderr + "]\n" + + " exitValue = " + getExitValue() + "\n"; + + System.err.println(msg); + } + + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return stdout + stderr; + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return stdout; + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return stderr; + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return exitValue; + } + + /** + * Get the contents of the output buffer (stdout and stderr) as list of strings. + * Output will be split by newlines. + * + * @return Contents of the output buffer as list of strings + */ + public List asLines() { + return asLines(getOutput()); + } + + private List asLines(String buffer) { + return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)")); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java b/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java new file mode 100644 index 00000000000..23976d8272f --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.process; + +public class OutputBuffer { + private final String stdout; + private final String stderr; + + /** + * Create an OutputBuffer, a class for storing and managing stdout and stderr + * results separately + * + * @param stdout stdout result + * @param stderr stderr result + */ + public OutputBuffer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + /** + * Returns the stdout result + * + * @return stdout result + */ + public String getStdout() { + return stdout; + } + + /** + * Returns the stderr result + * + * @return stderr result + */ + public String getStderr() { + return stderr; + } +} diff --git a/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java b/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java new file mode 100644 index 00000000000..3189a0fe277 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.process; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; + +public final class ProcessTools { + private static final class LineForwarder extends StreamPumper.LinePump { + private final PrintStream ps; + private final String prefix; + LineForwarder(String prefix, PrintStream os) { + this.ps = os; + this.prefix = prefix; + } + @Override + protected void processLine(String line) { + ps.println("[" + prefix + "] " + line); + } + } + + private ProcessTools() { + } + + /** + * Pumps stdout and stderr from running the process into a String. + * + * @param processHandler ProcessHandler to run. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException { + return getOutput(processBuilder.start()); + } + + /** + * Pumps stdout and stderr the running process into a String. + * + * @param process Process to pump. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(Process process) throws IOException { + ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); + ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer); + StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer); + Thread outPumperThread = new Thread(outPumper); + Thread errPumperThread = new Thread(errPumper); + + outPumperThread.setDaemon(true); + errPumperThread.setDaemon(true); + + outPumperThread.start(); + errPumperThread.start(); + + try { + process.waitFor(); + outPumperThread.join(); + errPumperThread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } + + return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString()); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + * @param name The process name + * @param processBuilder The process builder + * @return Returns the initialized process + * @throws IOException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder) + throws IOException { + return startProcess(name, processBuilder, (Consumer)null); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

It is possible to monitor the in-streams via the provided {@code consumer} + * @param name The process name + * @param consumer {@linkplain Consumer} instance to process the in-streams + * @param processBuilder The process builder + * @return Returns the initialized process + * @throws IOException + */ + @SuppressWarnings("overloads") + public static Process startProcess(String name, + ProcessBuilder processBuilder, + Consumer consumer) + throws IOException { + try { + return startProcess(name, processBuilder, consumer, null, -1, TimeUnit.NANOSECONDS); + } catch (InterruptedException | TimeoutException e) { + // will never happen + throw new RuntimeException(e); + } + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT + *

+ * @param name The process name + * @param processBuilder The process builder + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Predicate linePredicate, + long timeout, + TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, null, linePredicate, timeout, unit); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT and monitor the + * in-streams via the provided {@linkplain Consumer} + *

+ * @param name The process name + * @param processBuilder The process builder + * @param lineConsumer The {@linkplain Consumer} the lines will be forwarded to + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Consumer lineConsumer, + final Predicate linePredicate, + long timeout, + TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + System.out.println("["+name+"]:" + processBuilder.command().stream().collect(Collectors.joining(" "))); + Process p = processBuilder.start(); + StreamPumper stdout = new StreamPumper(p.getInputStream()); + StreamPumper stderr = new StreamPumper(p.getErrorStream()); + + stdout.addPump(new LineForwarder(name, System.out)); + stderr.addPump(new LineForwarder(name, System.err)); + if (lineConsumer != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + lineConsumer.accept(line); + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } + + + CountDownLatch latch = new CountDownLatch(1); + if (linePredicate != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + if (latch.getCount() > 0 && linePredicate.test(line)) { + latch.countDown(); + } + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } else { + latch.countDown(); + } + final Future stdoutTask = stdout.process(); + final Future stderrTask = stderr.process(); + + try { + if (timeout > -1) { + if (timeout == 0) { + latch.await(); + } else { + if (!latch.await(Utils.adjustTimeout(timeout), unit)) { + throw new TimeoutException(); + } + } + } + } catch (TimeoutException | InterruptedException e) { + System.err.println("Failed to start a process (thread dump follows)"); + for(Map.Entry s : Thread.getAllStackTraces().entrySet()) { + printStack(s.getKey(), s.getValue()); + } + + if (p.isAlive()) { + p.destroyForcibly(); + } + + stdoutTask.cancel(true); + stderrTask.cancel(true); + throw e; + } + + return new ProcessImpl(p, stdoutTask, stderrTask); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT. The warm-up will + * wait indefinitely. + *

+ * @param name The process name + * @param processBuilder The process builder + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + @SuppressWarnings("overloads") + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Predicate linePredicate) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, linePredicate, 0, TimeUnit.SECONDS); + } + + /** + * Get the process id of the current running Java process + * + * @return Process id + */ + public static long getProcessId() throws Exception { + return ProcessHandle.current().getPid(); + } + + /** + * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) + * + * @return String[] with platform specific arguments, empty if there are + * none + */ + public static String[] getPlatformSpecificVMArgs() { + + if (Platform.is64bit() && Platform.isSolaris()) { + return new String[] { "-d64" }; + } + + return new String[] {}; + } + + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested and + * with any platform specific arguments prepended + */ + public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { + return createJavaProcessBuilder(false, command); + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested, + * and with any platform specific arguments prepended. + * + * @param addTestVmAndJavaOptions If true, adds test.vm.opts and test.java.opts + * to the java arguments. + * @param command Arguments to pass to the java command. + * @return The ProcessBuilder instance representing the java command. + */ + public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception { + String javapath = JDKToolFinder.getJDKTool("java"); + + ArrayList args = new ArrayList<>(); + args.add(javapath); + Collections.addAll(args, getPlatformSpecificVMArgs()); + + if (addTestVmAndJavaOptions) { + // -cp is needed to make sure the same classpath is used whether the test is + // run in AgentVM mode or OtherVM mode. It was added to the hotspot version + // of this API as part of 8077608. However, for the jdk version it is only + // added when addTestVmAndJavaOptions is true in order to minimize + // disruption to existing JDK tests, which have yet to be tested with -cp + // being added. At some point -cp should always be added to be consistent + // with what the hotspot version does. + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + Collections.addAll(args, Utils.getTestJavaOpts()); + } + + Collections.addAll(args, command); + + // Reporting + StringBuilder cmdLine = new StringBuilder(); + for (String cmd : args) + cmdLine.append(cmd).append(' '); + System.out.println("Command line: [" + cmdLine.toString() + "]"); + + return new ProcessBuilder(args.toArray(new String[args.size()])); + } + + private static void printStack(Thread t, StackTraceElement[] stack) { + System.out.println("\t" + t + + " stack: (length = " + stack.length + ")"); + if (t != null) { + for (StackTraceElement stack1 : stack) { + System.out.println("\t" + stack1); + } + System.out.println(); + } + } + + /** + * Executes a test jvm process, waits for it to finish and returns the process output. + * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. + * The java from the test.jdk is used to execute the command. + * + * The command line will be like: + * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds + * + * The jvm process will have exited before this method returns. + * + * @param cmds User specifed arguments. + * @return The output from the process. + */ + public static OutputAnalyzer executeTestJvm(String... cmds) throws Exception { + ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); + return executeProcess(pb); + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * The process will have exited before this method returns. + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = null; + Process p = null; + boolean failed = false; + try { + p = pb.start(); + output = new OutputAnalyzer(p); + p.waitFor(); + + return output; + } catch (Throwable t) { + if (p != null) { + p.destroyForcibly().waitFor(); + } + + failed = true; + System.out.println("executeProcess() failed: " + t); + throw t; + } finally { + if (failed) { + System.err.println(getProcessLog(pb, output)); + } + } + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The output from the process. + */ + public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { + return executeProcess(new ProcessBuilder(cmds)); + } + + /** + * Used to log command line, stdout, stderr and exit code from an executed process. + * @param pb The executed process. + * @param output The output from the process. + */ + public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { + String stderr = output == null ? "null" : output.getStderr(); + String stdout = output == null ? "null" : output.getStdout(); + String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); + StringBuilder logMsg = new StringBuilder(); + final String nl = System.getProperty("line.separator"); + logMsg.append("--- ProcessLog ---" + nl); + logMsg.append("cmd: " + getCommandLine(pb) + nl); + logMsg.append("exitvalue: " + exitValue + nl); + logMsg.append("stderr: " + stderr + nl); + logMsg.append("stdout: " + stdout + nl); + + return logMsg.toString(); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + if (pb == null) { + return "null"; + } + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString().trim(); + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout, and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(String... cmds) + throws Throwable { + String cmdLine = Arrays.stream(cmds).collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout and returns the process output. + * + * The process will have exited before this method returns. + * + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(ProcessBuilder pb) + throws Throwable { + String cmdLine = pb.command().stream().collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + private static class ProcessImpl extends Process { + + private final Process p; + private final Future stdoutTask; + private final Future stderrTask; + + public ProcessImpl(Process p, Future stdoutTask, Future stderrTask) { + this.p = p; + this.stdoutTask = stdoutTask; + this.stderrTask = stderrTask; + } + + @Override + public OutputStream getOutputStream() { + return p.getOutputStream(); + } + + @Override + public InputStream getInputStream() { + return p.getInputStream(); + } + + @Override + public InputStream getErrorStream() { + return p.getErrorStream(); + } + + @Override + public int waitFor() throws InterruptedException { + int rslt = p.waitFor(); + waitForStreams(); + return rslt; + } + + @Override + public int exitValue() { + return p.exitValue(); + } + + @Override + public void destroy() { + p.destroy(); + } + + @Override + public long getPid() { + return p.getPid(); + } + + @Override + public boolean isAlive() { + return p.isAlive(); + } + + @Override + public Process destroyForcibly() { + return p.destroyForcibly(); + } + + @Override + public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException { + boolean rslt = p.waitFor(timeout, unit); + if (rslt) { + waitForStreams(); + } + return rslt; + } + + private void waitForStreams() throws InterruptedException { + try { + stdoutTask.get(); + } catch (ExecutionException e) { + } + try { + stderrTask.get(); + } catch (ExecutionException e) { + } + } + } +} diff --git a/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java b/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java new file mode 100644 index 00000000000..b1780c4ef08 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.process; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class StreamPumper implements Runnable { + + private static final int BUF_SIZE = 256; + + /** + * Pump will be called by the StreamPumper to process the incoming data + */ + abstract public static class Pump { + abstract void register(StreamPumper d); + } + + /** + * OutputStream -> Pump adapter + */ + final public static class StreamPump extends Pump { + private final OutputStream out; + public StreamPump(OutputStream out) { + this.out = out; + } + + @Override + void register(StreamPumper sp) { + sp.addOutputStream(out); + } + } + + /** + * Used to process the incoming data line-by-line + */ + abstract public static class LinePump extends Pump { + @Override + final void register(StreamPumper sp) { + sp.addLineProcessor(this); + } + + abstract protected void processLine(String line); + } + + private final InputStream in; + private final Set outStreams = new HashSet<>(); + private final Set linePumps = new HashSet<>(); + + private final AtomicBoolean processing = new AtomicBoolean(false); + private final FutureTask processingTask = new FutureTask<>(this, null); + + public StreamPumper(InputStream in) { + this.in = in; + } + + /** + * Create a StreamPumper that reads from in and writes to out. + * + * @param in The stream to read from. + * @param out The stream to write to. + */ + public StreamPumper(InputStream in, OutputStream out) { + this(in); + this.addOutputStream(out); + } + + /** + * Implements Thread.run(). Continuously read from {@code in} and write to + * {@code out} until {@code in} has reached end of stream. Abort on + * interruption. Abort on IOExceptions. + */ + @Override + public void run() { + try (BufferedInputStream is = new BufferedInputStream(in)) { + ByteArrayOutputStream lineBos = new ByteArrayOutputStream(); + byte[] buf = new byte[BUF_SIZE]; + int len = 0; + int linelen = 0; + + while ((len = is.read(buf)) > 0 && !Thread.interrupted()) { + for(OutputStream out : outStreams) { + out.write(buf, 0, len); + } + if (!linePumps.isEmpty()) { + int i = 0; + int lastcrlf = -1; + while (i < len) { + if (buf[i] == '\n' || buf[i] == '\r') { + int bufLinelen = i - lastcrlf - 1; + if (bufLinelen > 0) { + lineBos.write(buf, lastcrlf + 1, bufLinelen); + } + linelen += bufLinelen; + + if (linelen > 0) { + lineBos.flush(); + final String line = lineBos.toString(); + linePumps.stream().forEach((lp) -> { + lp.processLine(line); + }); + lineBos.reset(); + linelen = 0; + } + lastcrlf = i; + } + + i++; + } + if (lastcrlf == -1) { + lineBos.write(buf, 0, len); + linelen += len; + } else if (lastcrlf < len - 1) { + lineBos.write(buf, lastcrlf + 1, len - lastcrlf - 1); + linelen += len - lastcrlf - 1; + } + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + for(OutputStream out : outStreams) { + try { + out.flush(); + } catch (IOException e) {} + } + try { + in.close(); + } catch (IOException e) {} + } + } + + final void addOutputStream(OutputStream out) { + outStreams.add(out); + } + + final void addLineProcessor(LinePump lp) { + linePumps.add(lp); + } + + final public StreamPumper addPump(Pump ... pump) { + if (processing.get()) { + throw new IllegalStateException("Can not modify pumper while " + + "processing is in progress"); + } + for(Pump p : pump) { + p.register(this); + } + return this; + } + + final public Future process() { + if (!processing.compareAndSet(false, true)) { + throw new IllegalStateException("Can not re-run the processing"); + } + Thread t = new Thread(new Runnable() { + @Override + public void run() { + processingTask.run(); + } + }); + t.setDaemon(true); + t.start(); + + return processingTask; + } +} From 6ffba3b398f03d29ed0778e5ca6534540c1d89a3 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 3 Dec 2015 15:22:31 +0300 Subject: [PATCH 015/151] 8134152: Public API for java 8 DataFlavor fields do not have @since tag Reviewed-by: ssadetsky, alexsch --- .../share/classes/java/awt/datatransfer/DataFlavor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java index 5f05177be39..becfd0563ba 100644 --- a/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java @@ -289,6 +289,8 @@ public class DataFlavor implements Externalizable, Cloneable { * representationClass = String * mimeType = "text/html" * + * + * @since 1.8 */ public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection"); @@ -301,6 +303,8 @@ public class DataFlavor implements Externalizable, Cloneable { * representationClass = String * mimeType = "text/html" * + * + * @since 1.8 */ public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment"); @@ -314,6 +318,8 @@ public class DataFlavor implements Externalizable, Cloneable { * representationClass = String * mimeType = "text/html" * + * + * @since 1.8 */ public static DataFlavor allHtmlFlavor = initHtmlDataFlavor("all"); From 3096b2cc2f538b50b73971d8996c2c90a60da380 Mon Sep 17 00:00:00 2001 From: Rajeev Chamyal Date: Fri, 4 Dec 2015 09:56:50 +0400 Subject: [PATCH 016/151] 8067660: JFileChooser create new folder fails silently Reviewed-by: alexsch, psadhukhan --- .../swing/filechooser/FileSystemView.java | 13 +- .../JFileChooser/8067660/FileChooserTest.java | 250 ++++++++++++++++++ 2 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java index 54cd7c037d4..bbc35bf9c1d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java @@ -663,7 +663,9 @@ class UnixFileSystemView extends FileSystemView { if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); } else { - newFolder.mkdirs(); + if(!newFolder.mkdirs()) { + throw new IOException(newFolder.getAbsolutePath()); + } } return newFolder; @@ -773,7 +775,9 @@ class WindowsFileSystemView extends FileSystemView { if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); } else { - newFolder.mkdirs(); + if(!newFolder.mkdirs()) { + throw new IOException(newFolder.getAbsolutePath()); + } } return newFolder; @@ -842,9 +846,10 @@ class GenericFileSystemView extends FileSystemView { if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); } else { - newFolder.mkdirs(); + if(!newFolder.mkdirs()) { + throw new IOException(newFolder.getAbsolutePath()); + } } - return newFolder; } diff --git a/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java b/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java new file mode 100644 index 00000000000..acd49add15f --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8067660 + * @summary JFileChooser create new folder fails silently + * @requires (os.family == "windows") + * @run main/manual FileChooserTest + */ +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class FileChooserTest { + + private static boolean theTestPassed; + private static boolean testGeneratedInterrupt; + private static Thread mainThread; + private static int sleepTime = 30000; + public static JFileChooser fileChooser; + + private static void init() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + String[] instructions + = { + "1) Create a folder with read only permissions", + "2) Click on run test button.It will open a open dialog" + + " Navigate to the newly created read only folder", + "3) Click on the create new folder button in open dialog", + "4) If an error message does not pops up" + + "test failed otherwise passed.", + "5) Pressing Pass/Fail button will mark test as " + + "pass/fail and will shutdown JVM"}; + + Sysout.createDialogWithInstructions(instructions); + Sysout.printInstructions(instructions); + } + }); + } + + /** + * *************************************************** + * Standard Test Machinery Section DO NOT modify anything in this section -- + * it's a standard chunk of code which has all of the synchronisation + * necessary for the test harness. By keeping it the same in all tests, it + * is easier to read and understand someone else's test, as well as insuring + * that all tests behave correctly with the test harness. There is a section + * following this for test-defined classes + */ + public static void main(String args[]) throws Exception { + + mainThread = Thread.currentThread(); + try { + init(); + } catch (Exception ex) { + return; + } + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException ex) { + Sysout.dispose(); + if (!theTestPassed && testGeneratedInterrupt) { + throw new RuntimeException("Test Failed"); + } + } + if (!testGeneratedInterrupt) { + Sysout.dispose(); + throw new RuntimeException("Test Failed"); + } + } + + public static synchronized void pass() { + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + theTestPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } +} + +/** + * This is part of the standard test machinery. It creates a dialog (with the + * instructions), and is the interface for sending text messages to the user. To + * print the instructions, send an array of strings to Sysout.createDialog + * WithInstructions method. Put one line of instructions per array entry. To + * display a message for the tester to see, simply call Sysout.println with the + * string to be displayed. This mimics System.out.println but works within the + * test harness as well as standalone. + */ +class Sysout { + + private static TestDialog dialog; + private static JFrame frame; + + public static void createDialogWithInstructions(String[] instructions) { + frame = new JFrame(); + dialog = new TestDialog(frame, "Instructions"); + dialog.printInstructions(instructions); + dialog.setVisible(true); + println("Any messages for the tester will display here."); + } + + public static void printInstructions(String[] instructions) { + dialog.printInstructions(instructions); + } + + public static void println(String messageIn) { + dialog.displayMessage(messageIn); + } + + public static void dispose() { + Sysout.println("Shutting down the Java process.."); + if(FileChooserTest.fileChooser != null) { + FileChooserTest.fileChooser.cancelSelection(); + } + frame.dispose(); + dialog.dispose(); + } +} + +/** + * This is part of the standard test machinery. It provides a place for the test + * instructions to be displayed, and a place for interactive messages to the + * user to be displayed. To have the test instructions displayed, see Sysout. To + * have a message to the user be displayed, see Sysout. Do not call anything in + * this dialog directly. + */ +class TestDialog extends JDialog { + + private TextArea instructionsText; + private TextArea messageText; + private int maxStringLength = 80; + private Panel buttonP = new Panel(); + private JButton run = new JButton("Run"); + private JButton passB = new JButton("Pass"); + private JButton failB = new JButton("Fail"); + + public TestDialog(JFrame frame, String name) { + super(frame, name); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); + add("North", instructionsText); + + messageText = new TextArea("", 5, maxStringLength, scrollBoth); + add("Center", messageText); + + buttonP.add("East", run); + buttonP.add("East", passB); + buttonP.add("West", failB); + passB.setEnabled(false); + failB.setEnabled(false); + add("South", buttonP); + + run.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + FileChooserTest.fileChooser = new JFileChooser(); + FileChooserTest.fileChooser.showOpenDialog(null); + passB.setEnabled(true); + failB.setEnabled(true); + } + }); + + passB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + FileChooserTest.pass(); + } + }); + + failB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + FileChooserTest.fail(); + } + }); + pack(); + + setVisible(true); + } + + public void printInstructions(String[] instructions) { + instructionsText.setText(""); + + String printStr, remainingStr; + for (String instruction : instructions) { + remainingStr = instruction; + while (remainingStr.length() > 0) { + if (remainingStr.length() >= maxStringLength) { + int posOfSpace = remainingStr. + lastIndexOf(' ', maxStringLength - 1); + + if (posOfSpace <= 0) { + posOfSpace = maxStringLength - 1; + } + + printStr = remainingStr.substring(0, posOfSpace + 1); + remainingStr = remainingStr.substring(posOfSpace + 1); + } else { + printStr = remainingStr; + remainingStr = ""; + } + instructionsText.append(printStr + "\n"); + } + } + + } + + public void displayMessage(String messageIn) { + messageText.append(messageIn + "\n"); + } +} From 9c2dc1edf517c9e025972c167453594127db9a01 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 4 Dec 2015 13:52:21 +0300 Subject: [PATCH 017/151] 8140530: Creating a VolatileImage with size 0, 0 results in no longer working g2d.drawStri Reviewed-by: flar, serb --- .../sun/awt/image/SunVolatileImage.java | 4 ++ .../native/common/java2d/x11/X11SurfaceData.c | 9 ++++ .../image/VolatileImage/VolatileImageBug.java | 52 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java index 00c8911f696..1ee5c4019f1 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java @@ -70,6 +70,10 @@ public class SunVolatileImage extends VolatileImage { this.comp = comp; this.graphicsConfig = graphicsConfig; + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("Width (" + width + ")" + + " and height (" + height + ") cannot be <= 0"); + } this.width = width; this.height = height; this.forcedAccelSurfaceType = accType; diff --git a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c index d9af8ddf6e1..e6597a4723c 100644 --- a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c +++ b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c @@ -438,6 +438,15 @@ jboolean XShared_initSurface(JNIEnv *env, X11SDOps *xsdo, jint depth, jint width xsdo->drawable = drawable; xsdo->isPixmap = JNI_FALSE; } else { + /* + * width , height must be nonzero otherwise XCreatePixmap + * generates BadValue in error_handler + */ + if (width <= 0 || height <= 0) { + JNU_ThrowOutOfMemoryError(env, + "Can't create offscreen surface"); + return JNI_FALSE; + } xsdo->isPixmap = JNI_TRUE; /* REMIND: workaround for bug 4420220 on pgx32 boards: don't use DGA with pixmaps unless USE_DGA_PIXMAPS is set. diff --git a/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java b/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java new file mode 100644 index 00000000000..70ca2b00840 --- /dev/null +++ b/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java @@ -0,0 +1,52 @@ +/* + * 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. + */ +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.image.VolatileImage; + +/** + * @test + * @bug 8140530 + * @run main VolatileImageBug + * @summary Creating volatileimage(0,0) should throw IAE + */ +public class VolatileImageBug { + public static void main(String[] args) { + + boolean iaeThrown = false; + GraphicsEnvironment ge = GraphicsEnvironment. + getLocalGraphicsEnvironment(); + GraphicsConfiguration gc = ge.getDefaultScreenDevice(). + getDefaultConfiguration(); + try { + VolatileImage volatileImage = gc.createCompatibleVolatileImage(0, 0); + } catch (IllegalArgumentException iae) { + iaeThrown = true; + } + if (!iaeThrown) { + throw new RuntimeException ("IllegalArgumentException not thrown " + + "for createCompatibleVolatileImage(0,0)"); + } + } +} + From cdb4a75a00102ecf64d363b495b28499f7c3588c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Sat, 5 Dec 2015 09:48:43 -0800 Subject: [PATCH 018/151] 8144630: Use PrivilegedAction to create Thread in Marlin RendererStats Reviewed-by: prr, flar --- .../sun/java2d/marlin/RendererStats.java | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java index 6ddb5253372..4588bf270b3 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java @@ -25,6 +25,8 @@ package sun.java2d.marlin; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentLinkedQueue; @@ -32,6 +34,7 @@ import static sun.java2d.marlin.MarlinUtils.logInfo; import sun.java2d.marlin.stats.Histogram; import sun.java2d.marlin.stats.Monitor; import sun.java2d.marlin.stats.StatLong; +import sun.awt.util.ThreadGroupUtils; /** * This class gathers global rendering statistics for debugging purposes only @@ -237,22 +240,33 @@ public final class RendererStats implements MarlinConst { private RendererStats() { super(); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - dump(); - } - }); + AccessController.doPrivileged( + (PrivilegedAction) () -> { + final Thread hook = new Thread( + ThreadGroupUtils.getRootThreadGroup(), + new Runnable() { + @Override + public void run() { + dump(); + } + }, + "MarlinStatsHook" + ); + hook.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(hook); - if (useDumpThread) { - final Timer statTimer = new Timer("RendererStats"); - statTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - dump(); + if (useDumpThread) { + final Timer statTimer = new Timer("RendererStats"); + statTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + dump(); + } + }, statDump, statDump); } - }, statDump, statDump); - } + return null; + } + ); } void dump() { From e12241b6136000a4804f81e32a92b1dc5c863bc8 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 7 Dec 2015 12:31:25 +0100 Subject: [PATCH 019/151] 8144308: com/sun/jdi/SuspendThreadTest.java failed with "transport error 202: send failed: Broken pipe" Reviewed-by: sla --- jdk/test/com/sun/jdi/SuspendThreadTest.java | 119 +++++++++++--------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/jdk/test/com/sun/jdi/SuspendThreadTest.java b/jdk/test/com/sun/jdi/SuspendThreadTest.java index c70a58bff37..49b488864d5 100644 --- a/jdk/test/com/sun/jdi/SuspendThreadTest.java +++ b/jdk/test/com/sun/jdi/SuspendThreadTest.java @@ -42,6 +42,7 @@ import com.sun.jdi.request.*; class SuspendThreadTarg { public static long count; + public static boolean active = true; public static void bkpt() { count++; @@ -53,7 +54,7 @@ class SuspendThreadTarg { // We need this to be running so the bkpt // can be hit immediately when it is enabled // in the back-end. - while(count >= 0) { + while(active) { bkpt(); } System.out.println("Goodbye from SuspendThreadTarg, count = " + count); @@ -82,9 +83,9 @@ public class SuspendThreadTest extends TestScaffold { // to guard against spurious wakeups from bkptSignal.wait() boolean signalSent; // signal that a breakpoint has happened - Object bkptSignal = new Object() {}; + final private Object bkptSignal = new Object() {}; BreakpointRequest bkptRequest; - Field debuggeeCountField; + Field debuggeeCountField, debuggeeActiveField; // When we get a bkpt we want to disable the request, // resume the debuggee, and then re-enable the request @@ -119,65 +120,71 @@ public class SuspendThreadTest extends TestScaffold { /********** test core **********/ protected void runTests() throws Exception { - /* - * Get to the top of main() - * to determine targetClass and mainThread - */ - BreakpointEvent bpe = startToMain("SuspendThreadTarg"); - targetClass = (ClassType)bpe.location().declaringType(); - mainThread = bpe.thread(); - EventRequestManager erm = vm().eventRequestManager(); - - Location loc1 = findMethod(targetClass, "bkpt", "()V").location(); - - bkptRequest = erm.createBreakpointRequest(loc1); - - // Without this, it is a SUSPEND_ALL bkpt and the test will pass - bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); - bkptRequest.enable(); - - debuggeeCountField = targetClass.fieldByName("count"); try { - addListener (this); - } catch (Exception ex){ - ex.printStackTrace(); - failure("failure: Could not add listener"); - throw new Exception("SuspendThreadTest: failed", ex); - } + /* + * Get to the top of main() + * to determine targetClass and mainThread + */ + BreakpointEvent bpe = startToMain("SuspendThreadTarg"); + targetClass = (ClassType)bpe.location().declaringType(); + mainThread = bpe.thread(); + EventRequestManager erm = vm().eventRequestManager(); - int prevBkptCount; - vm().resume(); - synchronized (bkptSignal) { - while (bkptCount < maxBkpts) { - prevBkptCount = bkptCount; - // If we don't get a bkpt within 5 secs, - // the test fails - signalSent = false; - do { - try { - bkptSignal.wait(5000); - } catch (InterruptedException ee) { + Location loc1 = findMethod(targetClass, "bkpt", "()V").location(); + + bkptRequest = erm.createBreakpointRequest(loc1); + + // Without this, it is a SUSPEND_ALL bkpt and the test will pass + bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + bkptRequest.enable(); + + debuggeeCountField = targetClass.fieldByName("count"); + debuggeeActiveField = targetClass.fieldByName("active"); + try { + addListener (this); + } catch (Exception ex){ + ex.printStackTrace(); + failure("failure: Could not add listener"); + throw new Exception("SuspendThreadTest: failed", ex); + } + + int prevBkptCount; + vm().resume(); + synchronized (bkptSignal) { + while (bkptCount < maxBkpts) { + prevBkptCount = bkptCount; + // If we don't get a bkpt within 5 secs, + // the test fails + signalSent = false; + do { + try { + bkptSignal.wait(5000); + } catch (InterruptedException ee) { + } + } while (signalSent == false); + if (prevBkptCount == bkptCount) { + failure("failure: test hung"); + break; } - } while (signalSent == false); - if (prevBkptCount == bkptCount) { - failure("failure: test hung"); - break; } } - } - println("done with loop"); - bkptRequest.disable(); - removeListener(this); + println("done with loop"); + bkptRequest.disable(); + removeListener(this); - - /* - * deal with results of test - * if anything has called failure("foo") testFailed will be true - */ - if (!testFailed) { - println("SuspendThreadTest: passed"); - } else { - throw new Exception("SuspendThreadTest: failed"); + /* + * deal with results of test + * if anything has called failure("foo") testFailed will be true + */ + if (!testFailed) { + println("SuspendThreadTest: passed"); + } else { + throw new Exception("SuspendThreadTest: failed"); + } + } finally { + if (targetClass != null && debuggeeActiveField != null) { + targetClass.setValue(debuggeeActiveField, vm().mirrorOf(false)); + } } } } From 0258eeaf71bd949460365c0ec0ddf4992e4a4acd Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 7 Dec 2015 17:05:03 -0800 Subject: [PATCH 020/151] 8144677: jprt.properties should allow creating a user specified testset with custom build flavors and build targets Made setting jprt.build.flavors and jprt.build.targets more flexible Reviewed-by: dholmes, mikael --- make/jprt.properties | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/make/jprt.properties b/make/jprt.properties index d7f3eedfd53..0f828b56621 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -69,9 +69,20 @@ jprt.fastdebugOpen.build.configure.args=${jprt.fastdebug.build.configure.args} - jprt.productOpen.build.configure.args=${jprt.product.build.configure.args} --enable-openjdk-only jprt.optimizedOpen.build.configure.args=${jprt.product.build.configure.args} --enable-openjdk-only -# Select build flavors and build targets -jprt.build.flavors=${my.is.hotspot.job ? ${my.build.flavors.hotspot} : ${my.build.flavors.default}} -jprt.build.targets=${my.is.hotspot.job ? ${my.build.targets.hotspot} : ${my.build.targets.default}} + +# hotspot testset has custom build flavors and build targets +my.jprt.testsetHasCustomBuildFlavors.hotspot=true +my.jprt.testsetHasCustomBuildTargets.hotspot=true + +# determine if the specified testset has custom build flavors or build targets +my.jprt.testsetHasCustomBuildFlavors=${my.jprt.testsetHasCustomBuildFlavors.${jprt.test.set}} +my.jprt.testsetHasCustomBuildTargets=${my.jprt.testsetHasCustomBuildTargets.${jprt.test.set}} + +# Select build flavors and build targets based on the specified testset +jprt.build.flavors=${my.jprt.testsetHasCustomBuildFlavors ? \ + ${my.build.flavors.${jprt.test.set}} : ${my.build.flavors.default}} +jprt.build.targets=${my.jprt.testsetHasCustomBuildTargets ? \ + ${my.build.targets.${jprt.test.set}} : ${my.build.targets.default}} # Select test targets - jprt default for jprt.test.set is "default" jprt.test.targets=${my.test.targets.${jprt.test.set}} From 5bfc44dca23a7c9c29b280595df85cbb0417ec16 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 8 Dec 2015 11:25:47 +0300 Subject: [PATCH 021/151] 7160052: GlyphVector.setGlyphPosition can throw an exception on valid input Reviewed-by: jdv, serb --- .../classes/sun/font/StandardGlyphVector.java | 8 ++- .../TestStandardGlyphVectorBug.java | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java diff --git a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java index 06abf9de163..69f1d4babc2 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java +++ b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java @@ -445,13 +445,19 @@ public class StandardGlyphVector extends GlyphVector { } public void setGlyphPosition(int ix, Point2D pos) { + if (ix < 0 || ix > glyphs.length) { + throw new IndexOutOfBoundsException("ix = " + ix); + } + initPositions(); int ix2 = ix << 1; positions[ix2] = (float)pos.getX(); positions[ix2 + 1] = (float)pos.getY(); - clearCaches(ix); + if (ix < glyphs.length) { + clearCaches(ix); + } addFlags(FLAG_HAS_POSITION_ADJUSTMENTS); } diff --git a/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java b/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java new file mode 100644 index 00000000000..c4dbda40837 --- /dev/null +++ b/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; + +/** + * @test + * @bug 7160052 + * @run main TestStandardGlyphVectorBug + * @summary GlyphVector.setGlyphPosition should not throw an exception on valid input + */ +public class TestStandardGlyphVectorBug +{ + public static void main(String[] args) + { + Font defaultFont = new Font(null); + FontRenderContext defaultFrc = new FontRenderContext(new AffineTransform(), + true, true); + GlyphVector gv = defaultFont.createGlyphVector(defaultFrc, "test"); + + //this causes the bounds to be cached + //which is necessary to trigger the bug + gv.getGlyphLogicalBounds(0); + + //this correctly gets the position of the overall advance + Point2D glyphPosition = gv.getGlyphPosition(gv.getNumGlyphs()); + + // this sets the position of the overall advance, + // but also incorrectly tries to clear the bounds cache + // of a specific glyph indexed by the glyphIndex parameter + // even if the glyphIndex represents the overall advance + // (i.e. if glyphIndex == getNumGlyphs()) + gv.setGlyphPosition(gv.getNumGlyphs(), glyphPosition); + } +} From 7c018b1a000ff5f480b7c5acfd2770a23bb6e583 Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Wed, 9 Dec 2015 02:41:51 +0400 Subject: [PATCH 022/151] 8060137: Removing Text from TextField / TextArea is not possible after typing Reviewed-by: ssadetsky, psadhukhan --- .../share/classes/java/awt/TextComponent.java | 22 ++-- .../TextAreaEditing/TextAreaEditing.java | 28 ++++- .../TextFieldEditing/TextFieldEditing.java | 113 ++++++++++++++++++ 3 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java diff --git a/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java b/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java index 9e7c22a49bb..191412a30b7 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java +++ b/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java @@ -229,15 +229,21 @@ public class TextComponent extends Component implements Accessible { * @see java.awt.TextComponent#getText */ public synchronized void setText(String t) { - boolean skipTextEvent = (text == null || text.isEmpty()) - && (t == null || t.isEmpty()); - text = (t != null) ? t : ""; + if (t == null) { + t = ""; + } TextComponentPeer peer = (TextComponentPeer)this.peer; - // Please note that we do not want to post an event - // if TextArea.setText() or TextField.setText() replaces an empty text - // by an empty text, that is, if component's text remains unchanged. - if (peer != null && !skipTextEvent) { - peer.setText(text); + if (peer != null) { + text = peer.getText(); + // Please note that we do not want to post an event + // if TextArea.setText() or TextField.setText() replaces text + // by same text, that is, if component's text remains unchanged. + if (!t.equals(text)) { + text = t; + peer.setText(text); + } + } else { + text = t; } } diff --git a/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java b/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java index f3306784ef8..6b7dcfaf2c0 100644 --- a/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java +++ b/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java @@ -23,16 +23,23 @@ /* @test - @bug 8040322 + @bug 8040322 8060137 + @library ../../regtesthelpers + @build Util @summary Test TextArea APIs replaceRange, insert, append & setText @run main TextAreaEditing */ import java.awt.Frame; +import java.awt.Robot; import java.awt.TextArea; +import java.awt.AWTException; +import java.awt.event.KeyEvent; +import test.java.awt.regtesthelpers.Util; public class TextAreaEditing { + final static Robot robot = Util.createRobot(); private int testFailCount; private boolean isTestFail; private StringBuilder testFailMessage; @@ -61,6 +68,7 @@ public class TextAreaEditing { textArea.testReplaceRange(); textArea.testInsert(); textArea.testAppend(); + textArea.testSetText(); textArea.checkFailures(); textArea.dispose(); } @@ -119,6 +127,24 @@ public class TextAreaEditing { checkTest(""); } + private void testSetText() { + textArea.setText(null); + textArea.requestFocus(); + Util.clickOnComp(textArea, robot); + Util.waitForIdle(robot); + robot.keyPress(KeyEvent.VK_A); + robot.delay(5); + robot.keyRelease(KeyEvent.VK_A); + Util.waitForIdle(robot); + textArea.setText(null); + checkTest(""); + textArea.setText("CaseSensitive"); + checkTest("CaseSensitive"); + textArea.setText("caseSensitive"); + checkTest("caseSensitive"); + + } + private void checkTest(String str) { if (str != null && !str.equals(textArea.getText())) { testFailMessage.append("TestFail line : "); diff --git a/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java b/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java new file mode 100644 index 00000000000..503b6e35129 --- /dev/null +++ b/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8060137 + @library ../../regtesthelpers + @build Util + @summary Test TextField setText API + @run main TextFieldEditing + */ + +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.AWTException; +import java.awt.event.KeyEvent; +import test.java.awt.regtesthelpers.Util; + +public class TextFieldEditing { + + final static Robot robot = Util.createRobot(); + private int testFailCount; + private boolean isTestFail; + private StringBuilder testFailMessage; + + private Frame mainFrame; + private TextField textField; + + private TextFieldEditing() { + testFailMessage = new StringBuilder(); + mainFrame = new Frame(); + mainFrame.setSize(200, 200); + + textField = new TextField(); + mainFrame.add(textField); + mainFrame.setVisible(true); + } + + private void dispose() { + if (mainFrame != null) { + mainFrame.dispose(); + } + } + + public static void main(String[] s) { + TextFieldEditing textField = new TextFieldEditing(); + textField.testSetText(); + textField.checkFailures(); + textField.dispose(); + } + + private void testSetText() { + textField.setText(null); + textField.requestFocus(); + Util.clickOnComp(textField, robot); + Util.waitForIdle(robot); + robot.keyPress(KeyEvent.VK_A); + robot.delay(5); + robot.keyRelease(KeyEvent.VK_A); + Util.waitForIdle(robot); + textField.setText(null); + checkTest(""); + textField.setText("CaseSensitive"); + checkTest("CaseSensitive"); + textField.setText("caseSensitive"); + checkTest("caseSensitive"); + } + + private void checkTest(String str) { + if (str != null && !str.equals(textField.getText())) { + testFailMessage.append("TestFail line : "); + testFailMessage.append(Thread.currentThread().getStackTrace()[2]. + getLineNumber()); + testFailMessage.append(" TextField string : \""); + testFailMessage.append(textField.getText()); + testFailMessage.append("\" does not match expected string : \""); + testFailMessage.append(str).append("\""); + testFailMessage.append(System.getProperty("line.separator")); + testFailCount++; + isTestFail = true; + } + } + + private void checkFailures() { + if (isTestFail) { + testFailMessage.insert(0, "Test Fail count : " + testFailCount + + System.getProperty("line.separator")); + dispose(); + throw new RuntimeException(testFailMessage.toString()); + } + } +} From 18ace0f732d8acfd7bfaf8f18a50549d8822bf20 Mon Sep 17 00:00:00 2001 From: Manajit Halder Date: Tue, 8 Dec 2015 19:50:14 +0300 Subject: [PATCH 023/151] 7159591: [macosx] In SetFontTest there's no space for the second button Reviewed-by: arapte, serb --- jdk/test/java/awt/List/SetFontTest/SetFontTest.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/java/awt/List/SetFontTest/SetFontTest.html b/jdk/test/java/awt/List/SetFontTest/SetFontTest.html index db33b8c83a8..3ac0d99fc51 100644 --- a/jdk/test/java/awt/List/SetFontTest/SetFontTest.html +++ b/jdk/test/java/awt/List/SetFontTest/SetFontTest.html @@ -38,6 +38,6 @@

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

- + From f23d71b4f4f446dd99d0a7f70928a633c803a87e Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Wed, 9 Dec 2015 18:12:49 +0300 Subject: [PATCH 024/151] 8144915: TextField throws NPE Reviewed-by: ssadetsky, serb --- jdk/src/java.desktop/share/classes/java/awt/TextField.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/src/java.desktop/share/classes/java/awt/TextField.java b/jdk/src/java.desktop/share/classes/java/awt/TextField.java index 2dfd19c4128..7c5563088c3 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/TextField.java +++ b/jdk/src/java.desktop/share/classes/java/awt/TextField.java @@ -309,6 +309,9 @@ public class TextField extends TextComponent { * @return Returns text after replacing EOL characters. */ private static String replaceEOL(String text) { + if (text == null) { + return text; + } String[] strEOLs = {System.lineSeparator(), "\n"}; for (String eol : strEOLs) { if (text.contains(eol)) { From 3144cc4a273306a9f18d6a7863a5386c97b4915d Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 9 Dec 2015 18:56:59 +0300 Subject: [PATCH 025/151] 8143909: Behavior of null arguments not specified in javax.sound.midi.spi The specification change was reviewed by Florian Bomers also Reviewed-by: amenkov --- .../sound/AbstractMidiDeviceProvider.java | 8 +- .../sun/media/sound/JARSoundbankReader.java | 6 +- .../sound/RealTimeSequencerProvider.java | 5 +- .../com/sun/media/sound/SoftProvider.java | 5 +- .../media/sound/StandardMidiFileWriter.java | 34 ++- .../classes/javax/sound/midi/MidiSystem.java | 82 +++++-- .../sound/midi/spi/MidiDeviceProvider.java | 6 +- .../javax/sound/midi/spi/MidiFileReader.java | 8 +- .../javax/sound/midi/spi/MidiFileWriter.java | 8 +- .../javax/sound/midi/spi/SoundbankReader.java | 5 +- .../midi/MidiDeviceProvider/NullInfo.java | 71 ------ .../MidiDeviceProvider/ExpectedNPEOnNull.java | 94 ++++++++ .../MidiDeviceProvider/FakeInfo.java | 0 .../MidiDeviceProvider/UnsupportedInfo.java | 0 .../spi/MidiFileReader/ExpectedNPEOnNull.java | 130 +++++++++++ .../spi/MidiFileWriter/ExpectedNPEOnNull.java | 215 ++++++++++++++++++ .../SoundbankReader/ExpectedNPEOnNull.java | 94 ++++++++ 17 files changed, 647 insertions(+), 124 deletions(-) delete mode 100644 jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java create mode 100644 jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java rename jdk/test/javax/sound/midi/{ => spi}/MidiDeviceProvider/FakeInfo.java (100%) rename jdk/test/javax/sound/midi/{ => spi}/MidiDeviceProvider/UnsupportedInfo.java (100%) create mode 100644 jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java create mode 100644 jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java create mode 100644 jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java index 8d0003cc987..6ff1ccde6b0 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -25,10 +25,11 @@ package com.sun.media.sound; +import java.util.Objects; + import javax.sound.midi.MidiDevice; import javax.sound.midi.spi.MidiDeviceProvider; - /** * Super class for MIDI input or output device provider. * @@ -127,7 +128,8 @@ public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider { } @Override - public final MidiDevice getDevice(MidiDevice.Info info) { + public final MidiDevice getDevice(final MidiDevice.Info info) { + Objects.requireNonNull(info); if (info instanceof Info) { readDeviceInfos(); MidiDevice[] devices = getDeviceCache(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java index 32fc90ffbb7..30c49810771 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.media.sound; import java.io.BufferedReader; @@ -32,6 +33,8 @@ import java.io.InputStreamReader; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Objects; + import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.Soundbank; import javax.sound.midi.spi.SoundbankReader; @@ -112,6 +115,7 @@ public final class JARSoundbankReader extends SoundbankReader { public Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException { + Objects.requireNonNull(stream); return null; } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java index fa5bfa1afbf..32ca9ff5331 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,8 @@ package com.sun.media.sound; +import java.util.Objects; + import javax.sound.midi.MidiDevice; import javax.sound.midi.spi.MidiDeviceProvider; @@ -42,6 +44,7 @@ public final class RealTimeSequencerProvider extends MidiDeviceProvider { @Override public MidiDevice getDevice(final MidiDevice.Info info) { + Objects.requireNonNull(info); if (RealTimeSequencer.info.equals(info)) { return new RealTimeSequencer(); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java index 89d85362539..e4bc1a7e342 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -25,6 +25,8 @@ package com.sun.media.sound; +import java.util.Objects; + import javax.sound.midi.MidiDevice; import javax.sound.midi.spi.MidiDeviceProvider; @@ -42,6 +44,7 @@ public final class SoftProvider extends MidiDeviceProvider { @Override public MidiDevice getDevice(final MidiDevice.Info info) { + Objects.requireNonNull(info); if (SoftSynthesizer.info.equals(info)) { return new SoftSynthesizer(); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java index f03921e72df..cc75e40e251 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,22 @@ package com.sun.media.sound; -import java.io.DataOutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; -import java.io.SequenceInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.SequenceInputStream; +import java.util.Objects; import javax.sound.midi.InvalidMidiDataException; -import javax.sound.midi.MidiEvent; import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; import javax.sound.midi.Sequence; import javax.sound.midi.ShortMessage; import javax.sound.midi.SysexMessage; @@ -115,24 +116,16 @@ public final class StandardMidiFileWriter extends MidiFileWriter { return typesArray; } - public boolean isFileTypeSupported(int type) { - for(int i=0; i providers = getMidiFileReaders(); MidiFileFormat format = null; @@ -602,11 +613,13 @@ public class MidiSystem { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the URL + * @throws NullPointerException if {@code url} is {@code null} * @see #getMidiFileFormat(InputStream) * @see #getMidiFileFormat(File) */ - public static MidiFileFormat getMidiFileFormat(URL url) - throws InvalidMidiDataException, IOException { + public static MidiFileFormat getMidiFileFormat(final URL url) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(url); List providers = getMidiFileReaders(); MidiFileFormat format = null; @@ -646,11 +659,13 @@ public class MidiSystem { * @throws InvalidMidiDataException if the {@code File} does not point to * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the file + * @throws NullPointerException if {@code file} is {@code null} * @see #getMidiFileFormat(InputStream) * @see #getMidiFileFormat(URL) */ - public static MidiFileFormat getMidiFileFormat(File file) - throws InvalidMidiDataException, IOException { + public static MidiFileFormat getMidiFileFormat(final File file) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(file); List providers = getMidiFileReaders(); MidiFileFormat format = null; @@ -699,11 +714,13 @@ public class MidiSystem { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the stream + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ - public static Sequence getSequence(InputStream stream) - throws InvalidMidiDataException, IOException { + public static Sequence getSequence(final InputStream stream) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(stream); List providers = getMidiFileReaders(); Sequence sequence = null; @@ -743,9 +760,11 @@ public class MidiSystem { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the URL + * @throws NullPointerException if {@code url} is {@code null} */ - public static Sequence getSequence(URL url) - throws InvalidMidiDataException, IOException { + public static Sequence getSequence(final URL url) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(url); List providers = getMidiFileReaders(); Sequence sequence = null; @@ -787,9 +806,11 @@ public class MidiSystem { * @throws InvalidMidiDataException if the File does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ - public static Sequence getSequence(File file) - throws InvalidMidiDataException, IOException { + public static Sequence getSequence(final File file) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(file); List providers = getMidiFileReaders(); Sequence sequence = null; @@ -870,8 +891,10 @@ public class MidiSystem { * @param sequence the sequence for which MIDI file type support is queried * @return the set of unique supported file types. If no file types are * supported, returns an array of length 0. + * @throws NullPointerException if {@code sequence} is {@code null} */ - public static int[] getMidiFileTypes(Sequence sequence) { + public static int[] getMidiFileTypes(final Sequence sequence) { + Objects.requireNonNull(sequence); List providers = getMidiFileWriters(); Set allTypes = new HashSet<>(); @@ -903,8 +926,11 @@ public class MidiSystem { * @param sequence the sequence for which file writing support is queried * @return {@code true} if the file type is supported for this sequence, * otherwise {@code false} + * @throws NullPointerException if {@code sequence} is {@code null} */ - public static boolean isFileTypeSupported(int fileType, Sequence sequence) { + public static boolean isFileTypeSupported(final int fileType, + final Sequence sequence) { + Objects.requireNonNull(sequence); List providers = getMidiFileWriters(); @@ -929,10 +955,15 @@ public class MidiSystem { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file format is not supported by * the system + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ - public static int write(Sequence in, int fileType, OutputStream out) throws IOException { + public static int write(final Sequence in, final int fileType, + final OutputStream out) throws IOException { + Objects.requireNonNull(in); + Objects.requireNonNull(out); List providers = getMidiFileWriters(); //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences @@ -963,10 +994,15 @@ public class MidiSystem { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by the * system + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ - public static int write(Sequence in, int type, File out) throws IOException { + public static int write(final Sequence in, final int type, final File out) + throws IOException { + Objects.requireNonNull(in); + Objects.requireNonNull(out); List providers = getMidiFileWriters(); //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java index 97c9d92b7f0..4f820b497d7 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package javax.sound.midi.spi; import java.util.Arrays; +import java.util.Objects; import javax.sound.midi.MidiDevice; @@ -46,8 +47,10 @@ public abstract class MidiDeviceProvider { * is queried * @return {@code true} if the specified device is supported, otherwise * {@code false} + * @throws NullPointerException if {@code info} is {@code null} */ public boolean isDeviceSupported(final MidiDevice.Info info) { + Objects.requireNonNull(info); return Arrays.asList(getDeviceInfo()).contains(info); } @@ -67,6 +70,7 @@ public abstract class MidiDeviceProvider { * @throws IllegalArgumentException if the info object specified does not * match the info object for a device supported by this * {@code MidiDeviceProvider} + * @throws NullPointerException if {@code info} is {@code null} */ public abstract MidiDevice getDevice(MidiDevice.Info info); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java index bbdca9e97bb..f1c3b6f6ff5 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ @@ -76,6 +77,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException, IOException; @@ -90,6 +92,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the {@code File} does not point to * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException, IOException; @@ -110,6 +113,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ @@ -126,6 +130,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract Sequence getSequence(URL url) throws InvalidMidiDataException, IOException; @@ -141,6 +146,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the {@code File} does not point to * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract Sequence getSequence(File file) throws InvalidMidiDataException, IOException; diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java index a1800f7f701..9a3fdcbc62e 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ public abstract class MidiFileWriter { * queried * @return array of file types. If no file types are supported, returns an * array of length 0. + * @throws NullPointerException if {@code sequence} is {@code null} */ public abstract int[] getMidiFileTypes(Sequence sequence); @@ -88,6 +89,7 @@ public abstract class MidiFileWriter { * @param sequence the sequence for which file writing support is queried * @return {@code true} if the file type is supported for this sequence, * otherwise {@code false} + * @throws NullPointerException if {@code sequence} is {@code null} */ public boolean isFileTypeSupported(int fileType, Sequence sequence) { @@ -111,6 +113,8 @@ public abstract class MidiFileWriter { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by * this file writer + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ @@ -129,6 +133,8 @@ public abstract class MidiFileWriter { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by * this file writer + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java index 501c18b6ad5..8690b0d18ed 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ public abstract class SoundbankReader { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * soundbank data recognized by this soundbank reader * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException; @@ -64,6 +65,7 @@ public abstract class SoundbankReader { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI soundbank data recognized by this soundbank reader * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code stream} is {@code null} */ public abstract Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException; @@ -76,6 +78,7 @@ public abstract class SoundbankReader { * @throws InvalidMidiDataException if the file does not point to valid MIDI * soundbank data recognized by this soundbank reader * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract Soundbank getSoundbank(File file) throws InvalidMidiDataException, IOException; diff --git a/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java b/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java deleted file mode 100644 index 9fa00c03172..00000000000 --- a/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.util.Collection; -import java.util.HashSet; - -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.spi.MidiDeviceProvider; - -import static java.util.ServiceLoader.load; - -/** - * @test - * @bug 8058115 - * @summary MidiDeviceProvider shouldn't returns incorrect results or throw NPE - * in case of null MidiDevice.Info - * @author Sergey Bylokhov - */ -public final class NullInfo { - - public static void main(final String[] args) { - // MidiSystem API - try { - MidiSystem.getMidiDevice(null); - throw new RuntimeException("IllegalArgumentException expected"); - } catch (final MidiUnavailableException e) { - throw new RuntimeException("IllegalArgumentException expected", e); - } catch (final IllegalArgumentException ignored) { - // expected - } - // MidiDeviceProvider API - final Collection errors = new HashSet<>(); - for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) { - try { - if (mdp.isDeviceSupported(null)) { - throw new RuntimeException("null is supported"); - } - final MidiDevice device = mdp.getDevice(null); - System.err.println("MidiDevice: " + device); - throw new RuntimeException("IllegalArgumentException expected"); - } catch (final IllegalArgumentException e) { - errors.add(e.getMessage()); - } - } - if (errors.size() != 1) { - throw new RuntimeException("Wrong number of messages:" + errors); - } - } -} diff --git a/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..efb57eeeae2 --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +import java.util.Objects; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.spi.MidiDeviceProvider; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) { + testMDP(mdp); + } + testMDP(customMDP); + } + + /** + * Tests the part of MidiSystem API, which implemented via + * MidiDeviceProvider. + */ + private static void testMS() throws Exception { + // MidiSystem#getMidiDevice(MidiDevice.Info) + try { + MidiSystem.getMidiDevice(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the MidiDeviceProvider API directly. + */ + private static void testMDP(final MidiDeviceProvider mdp) throws Exception { + // MidiDeviceProvider#isDeviceSupported(Info) + try { + mdp.isDeviceSupported(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiDeviceProvider#getDevice(Info) + try { + mdp.getDevice(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests some default implementation of MidiDeviceProvider API, using the + * custom {@code MidiDeviceProvider}, which support nothing. + */ + static MidiDeviceProvider customMDP = new MidiDeviceProvider() { + @Override + public MidiDevice.Info[] getDeviceInfo() { + return new MidiDevice.Info[0]; + } + + @Override + public MidiDevice getDevice(MidiDevice.Info info) { + Objects.requireNonNull(info); + return null; + } + }; +} diff --git a/jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/FakeInfo.java similarity index 100% rename from jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java rename to jdk/test/javax/sound/midi/spi/MidiDeviceProvider/FakeInfo.java diff --git a/jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/UnsupportedInfo.java similarity index 100% rename from jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java rename to jdk/test/javax/sound/midi/spi/MidiDeviceProvider/UnsupportedInfo.java diff --git a/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..bb4b75f3302 --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.spi.MidiFileReader; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final MidiFileReader mfr : load(MidiFileReader.class)) { + testMFR(mfr); + } + } + + /** + * Tests the part of MidiSystem API, which implemented via MidiFileReader. + */ + private static void testMS() throws Exception { + // MidiSystem#getMidiFileFormat(InputStream) + try { + MidiSystem.getMidiFileFormat((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getMidiFileFormat(URL) + try { + MidiSystem.getMidiFileFormat((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getMidiFileFormat(File) + try { + MidiSystem.getMidiFileFormat((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSequence(InputStream) + try { + MidiSystem.getSequence((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSequence(URL) + try { + MidiSystem.getSequence((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSequence(File) + try { + MidiSystem.getSequence((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the MidiFileReader API directly. + */ + private static void testMFR(final MidiFileReader mfr) throws Exception { + // MidiFileReader#getMidiFileFormat(InputStream) + try { + mfr.getMidiFileFormat((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getMidiFileFormat(URL) + try { + mfr.getMidiFileFormat((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getMidiFileFormat(File) + try { + mfr.getMidiFileFormat((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getSequence(InputStream) + try { + mfr.getSequence((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getSequence(URL) + try { + mfr.getSequence((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getSequence(File) + try { + mfr.getSequence((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } +} diff --git a/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..6a96dbe6b52 --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java @@ -0,0 +1,215 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.OutputStream; +import java.util.Objects; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.spi.MidiFileWriter; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final MidiFileWriter mfw : load(MidiFileWriter.class)) { + testMFW(mfw); + } + testMFW(customMFW); + } + + /** + * Tests the part of MidiSystem API, which implemented via MidiFileWriter. + */ + private static void testMS() throws Exception { + // MidiSystem#getMidiFileTypes(Sequence) + try { + MidiSystem.getMidiFileTypes(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + + // MidiSystem#isFileTypeSupported(int, Sequence) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.isFileTypeSupported(type, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiSystem#write(Sequence, int, OutputStream) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, new NullOutputStream()); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(new Sequence(0, 0), type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiSystem#write(Sequence, int, File) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, new File("")); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(new Sequence(0, 0), type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + + /** + * Tests the MidiFileWriter API directly. + */ + private static void testMFW(final MidiFileWriter mfw) throws Exception { + // MidiFileWriter#getMidiFileTypes(Sequence) + try { + mfw.getMidiFileTypes(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileWriter#isFileTypeSupported(int, Sequence) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.isFileTypeSupported(type, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiFileWriter#write(Sequence, int, OutputStream) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, new NullOutputStream()); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(new Sequence(0, 0), type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiFileWriter#write(Sequence, int, File) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, new File("")); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(new Sequence(0, 0), type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + /** + * Tests some default implementation of MidiFileWriter API, using the custom + * {@code MidiFileWriter}, which support nothing. + */ + static MidiFileWriter customMFW = new MidiFileWriter() { + @Override + public int[] getMidiFileTypes() { + return new int[0]; + } + + @Override + public int[] getMidiFileTypes(Sequence sequence) { + Objects.requireNonNull(sequence); + return new int[0]; + } + + @Override + public int write(Sequence in, int fileType, OutputStream out) { + Objects.requireNonNull(in); + Objects.requireNonNull(out); + return 0; + } + + @Override + public int write(Sequence in, int fileType, File out) { + Objects.requireNonNull(in); + Objects.requireNonNull(out); + return 0; + } + }; + + private static final class NullOutputStream extends OutputStream { + + @Override + public void write(final int b) { + //do nothing + } + } +} diff --git a/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..6ce3742fc9e --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.spi.SoundbankReader; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final SoundbankReader sbr : load(SoundbankReader.class)) { + testSBR(sbr); + } + } + + /** + * Tests the part of MidiSystem API, which implemented via SoundbankReader. + */ + private static void testMS() throws Exception { + // MidiSystem#getSoundbank(InputStream) + try { + MidiSystem.getSoundbank((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSoundbank(URL) + try { + MidiSystem.getSoundbank((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSoundbank(File) + try { + MidiSystem.getSoundbank((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the SoundbankReader API directly. + */ + private static void testSBR(final SoundbankReader sbr) throws Exception { + // SoundbankReader#getSoundbank(InputStream) + try { + sbr.getSoundbank((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // SoundbankReader#getSoundbank(URL) + try { + sbr.getSoundbank((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // SoundbankReader#getSoundbank(File) + try { + sbr.getSoundbank((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } +} From dcf0684317b79872294bc77c3a668ba237e30d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Wed, 9 Dec 2015 13:59:45 -0800 Subject: [PATCH 026/151] 8144828: Marlin renderer causes unaligned write accesses Reviewed-by: prr, flar --- .../sun/java2d/marlin/MarlinCache.java | 25 ++++++++++++++----- .../sun/java2d/marlin/MarlinConst.java | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java index a281b4e5ecf..9aa35132772 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java @@ -156,8 +156,6 @@ public final class MarlinCache implements MarlinConst { // rewritten to avoid division: || (width * heightSubPixel) > ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG); -// ((edgeSumDeltaY - heightSubPixel) * RLE_THRESHOLD); -// ((edgeSumDeltaY - heightSubPixel) << BLOCK_TH_LG); if (doTrace && !useRLE) { final float meanCrossings @@ -293,8 +291,10 @@ public final class MarlinCache implements MarlinConst { // update row index to current position: rowAAChunkIndex[row] = pos; - // determine need array size (may overflow): - final long needSize = pos + (px_bbox1 - px0); + // determine need array size: + // for RLE encoding, position must be aligned to 4 bytes (int): + // align - 1 = 3 so add +3 and round-off by mask ~3 = -4 + final long needSize = pos + ((px_bbox1 - px0 + 3) & -4); // update next position (bytes): rowAAChunkPos = needSize; @@ -401,8 +401,7 @@ public final class MarlinCache implements MarlinConst { // determine need array size: // pessimistic: max needed size = deltaX x 4 (1 int) - final int maxLen = (to - from); - final long needSize = initialPos + (maxLen << 2); + final long needSize = initialPos + ((to - from) << 2); // update row data: OffHeapArray _rowAAChunk = rowAAChunk; @@ -465,6 +464,13 @@ public final class MarlinCache implements MarlinConst { // note: last pixel exclusive (>= 0) // note: it should check X is smaller than 23bits (overflow)! + // check address alignment to 4 bytes: + if (doCheckUnsafe) { + if ((addr_off & 3) != 0) { + MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); + } + } + // special case to encode entries into a single int: if (val == 0) { _unsafe.putInt(addr_off, @@ -521,6 +527,13 @@ public final class MarlinCache implements MarlinConst { // note: last pixel exclusive (>= 0) // note: it should check X is smaller than 23bits (overflow)! + // check address alignment to 4 bytes: + if (doCheckUnsafe) { + if ((addr_off & 3) != 0) { + MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); + } + } + // special case to encode entries into a single int: if (val == 0) { _unsafe.putInt(addr_off, diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java index 6ff24a04b64..e799504318d 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java @@ -40,6 +40,8 @@ interface MarlinConst { // log misc.Unsafe alloc/realloc/free static final boolean logUnsafeMalloc = enableLogs && MarlinProperties.isLogUnsafeMalloc(); + // do check unsafe alignment: + static final boolean doCheckUnsafe = false; // do statistics static final boolean doStats = enableLogs && MarlinProperties.isDoStats(); From 5999226f522df00e970dbc84a94f11df0350f605 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 9 Dec 2015 15:20:39 -0800 Subject: [PATCH 027/151] 8137106: EUDC (End User Defined Characters) are not displayed on Windows with Java 8u60+ Reviewed-by: serb, jgodinez --- .../share/classes/sun/font/TrueTypeFont.java | 33 ++++++++++++++----- .../classes/sun/awt/Win32FontManager.java | 2 +- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java index c4893b6dd60..7668b6572a8 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java +++ b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java @@ -176,6 +176,13 @@ public class TrueTypeFont extends FileFont { private String localeFamilyName; private String localeFullName; + public TrueTypeFont(String platname, Object nativeNames, int fIndex, + boolean javaRasterizer) + throws FontFormatException + { + this(platname, nativeNames, fIndex, javaRasterizer, true); + } + /** * - does basic verification of the file * - reads the header table for this font (within a collection) @@ -186,14 +193,17 @@ public class TrueTypeFont extends FileFont { * or fails verification, or there's no usable cmap */ public TrueTypeFont(String platname, Object nativeNames, int fIndex, - boolean javaRasterizer) + boolean javaRasterizer, boolean useFilePool) throws FontFormatException { super(platname, nativeNames); useJavaRasterizer = javaRasterizer; fontRank = Font2D.TTF_RANK; try { - verify(); + verify(useFilePool); init(fIndex); + if (!useFilePool) { + close(); + } } catch (Throwable t) { close(); if (t instanceof FontFormatException) { @@ -280,6 +290,10 @@ public class TrueTypeFont extends FileFont { } + private synchronized FileChannel open() throws FontFormatException { + return open(true); + } + /* This is intended to be called, and the returned value used, * from within a block synchronized on this font object. * ie the channel returned may be nulled out at any time by "close()" @@ -287,7 +301,8 @@ public class TrueTypeFont extends FileFont { * Deadlock warning: FontManager.addToPool(..) acquires a global lock, * which means nested locks may be in effect. */ - private synchronized FileChannel open() throws FontFormatException { + private synchronized FileChannel open(boolean usePool) + throws FontFormatException { if (disposerRecord.channel == null) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().info("open TTF: " + platName); @@ -306,9 +321,11 @@ public class TrueTypeFont extends FileFont { }); disposerRecord.channel = raf.getChannel(); fileSize = (int)disposerRecord.channel.size(); - FontManager fm = FontManagerFactory.getInstance(); - if (fm instanceof SunFontManager) { - ((SunFontManager) fm).addToPool(this); + if (usePool) { + FontManager fm = FontManagerFactory.getInstance(); + if (fm instanceof SunFontManager) { + ((SunFontManager) fm).addToPool(this); + } } } catch (NullPointerException e) { close(); @@ -492,8 +509,8 @@ public class TrueTypeFont extends FileFont { } } - private void verify() throws FontFormatException { - open(); + private void verify(boolean usePool) throws FontFormatException { + open(usePool); } /* sizes, in bytes, of TT/TTC header records */ diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java index ee50f24a293..815393eaa1c 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java @@ -61,7 +61,7 @@ public final class Win32FontManager extends SunFontManager { * enumerate (allow direct use) of EUDC fonts. */ eudcFont = new TrueTypeFont(eudcFile, null, 0, - true); + true, false); } catch (FontFormatException e) { } } From 7d9d3a469949a3874f35ebacb140e0aaf49c12f0 Mon Sep 17 00:00:00 2001 From: Avik Niyogi Date: Thu, 10 Dec 2015 14:21:44 +0300 Subject: [PATCH 028/151] 8139169: [macosx] Action registered for keyboard shortcut is called twice Reviewed-by: serb, alexsch --- .../native/libawt_lwawt/awt/CMenuItem.m | 300 ++++++++++-------- .../8139169/ScreenMenuBarInputTwice.java | 234 ++++++++++++++ 2 files changed, 405 insertions(+), 129 deletions(-) create mode 100644 jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m index 8e483468074..28e4f386d78 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m @@ -24,6 +24,7 @@ */ #import +#include #import "CMenuItem.h" #import "CMenu.h" @@ -40,7 +41,7 @@ @implementation CMenuItem - (id) initWithPeer:(jobject)peer asSeparator: (NSNumber *) asSeparator{ -AWT_ASSERT_APPKIT_THREAD; + AWT_ASSERT_APPKIT_THREAD; self = [super initWithPeer:peer]; if (self) { if ([asSeparator boolValue]) { @@ -63,13 +64,48 @@ AWT_ASSERT_APPKIT_THREAD; - (BOOL) worksWhenModal { return YES; } +// This is a method written using Carbon framework methods to remove +// All modifiers including "Shift" modifier. +// Example 1: Shortcut set is "Command Shift m" returns "m" +// Example 2: Shortcut set is "Command m" returns "m" +// Example 3: Shortcut set is "Alt Shift ," returns "," + +CFStringRef createStringForKey(CGKeyCode keyCode) +{ + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); +// currentKeyboard now contains the current input source + CFDataRef layoutData = + TISGetInputSourceProperty(currentKeyboard, + kTISPropertyUnicodeKeyLayoutData); +// the UNICODE keyLayout is fetched from currentKeyboard in layoutData + const UCKeyboardLayout *keyboardLayout = + (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); +// A read-only data pointer is fetched from layoutData + UInt32 keysDown = 0; + UniChar chars[4]; + UniCharCount realLength; + + UCKeyTranslate(keyboardLayout, + keyCode, + kUCKeyActionDisplay, + 0, + LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + &keysDown, + sizeof(chars) / sizeof(chars[0]), + &realLength, + chars); + CFRelease(currentKeyboard); +// Converts keyCode, modifier and dead-key state into UNICODE characters + return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); +} // Events - (void)handleAction:(NSMenuItem *)sender { -AWT_ASSERT_APPKIT_THREAD; + AWT_ASSERT_APPKIT_THREAD; JNIEnv *env = [ThreadUtilities getJNIEnv]; -JNF_COCOA_ENTER(env); - + JNF_COCOA_ENTER(env); + // If we are called as a result of user pressing a shortcut, do nothing, // because AVTView has already sent corresponding key event to the Java // layer from performKeyEquivalent. @@ -82,31 +118,37 @@ JNF_COCOA_ENTER(env); NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent]; if ([currEvent type] == NSKeyDown) { NSString *menuKey = [sender keyEquivalent]; - NSString *eventKey = [currEvent charactersIgnoringModifiers]; - - // Apple uses characters from private Unicode range for some of the - // keys, so we need to do the same translation here that we do - // for the regular key down events - if ([eventKey length] == 1) { - unichar origChar = [eventKey characterAtIndex:0]; - unichar newChar = NsCharToJavaChar(origChar, 0); - if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) { - newChar = origChar; - } - - eventKey = [NSString stringWithCharacters: &newChar length: 1]; - } - +// If shortcut is "Command Shift ," the menuKey gets the value "," +// But [currEvent charactersIgnoringModifiers]; returns "<" and not "," +// because the charactersIgnoreingModifiers does not ignore "Shift" +// So a shortcut like "Command Shift m" will return "M" where as the +// MenuKey will have the value "m". To remove this issue the below +// createStringForKey is used. + NSString *eventKey = createStringForKey([currEvent keyCode]); + +// Apple uses characters from private Unicode range for some of the +// keys, so we need to do the same translation here that we do +// for the regular key down events + if ([eventKey length] == 1) { + unichar origChar = [eventKey characterAtIndex:0]; + unichar newChar = NsCharToJavaChar(origChar, 0); + if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) { + newChar = origChar; + } + + eventKey = [NSString stringWithCharacters: &newChar length: 1]; + } + NSWindow *keyWindow = [NSApp keyWindow]; if ([menuKey isEqualToString:eventKey] && keyWindow != nil) { return; } } - + if (fIsCheckbox) { static JNF_CLASS_CACHE(jc_CCheckboxMenuItem, "sun/lwawt/macosx/CCheckboxMenuItem"); static JNF_MEMBER_CACHE(jm_ckHandleAction, jc_CCheckboxMenuItem, "handleAction", "(Z)V"); - + // Send the opposite of what's currently checked -- the action // indicates what state we're going to. NSInteger state = [sender state]; @@ -115,26 +157,26 @@ JNF_COCOA_ENTER(env); } else { static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem"); static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event) - + NSUInteger modifiers = [currEvent modifierFlags]; jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO); - + JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event) } -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers { - + NSUInteger modifierMask = 0; - + if (![theKeyEquivalent isEqualToString:@""]) { // Force the key equivalent to lower case if not using the shift key. // Otherwise AppKit will draw a Shift glyph in the menu. if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) == 0) { theKeyEquivalent = [theKeyEquivalent lowercaseString]; } - + // Hack for the question mark -- SHIFT and / means use the question mark. if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) != 0 && [theKeyEquivalent isEqualToString:@"/"]) @@ -142,10 +184,10 @@ JNF_COCOA_EXIT(env); theKeyEquivalent = @"?"; modifiers &= ~java_awt_event_KeyEvent_SHIFT_MASK; } - + modifierMask = JavaModifiersToNsKeyModifiers(modifiers, NO); } - + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [fMenuItem setKeyEquivalent:theKeyEquivalent]; [fMenuItem setKeyEquivalentModifierMask:modifierMask]; @@ -154,14 +196,14 @@ JNF_COCOA_EXIT(env); } - (void) setJavaImage:(NSImage *)theImage { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setImage:theImage]; }]; } - (void) setJavaToolTipText:(NSString *)theText { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setToolTip:theText]; }]; @@ -169,11 +211,11 @@ JNF_COCOA_EXIT(env); - (void)setJavaEnabled:(BOOL) enabled { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ @synchronized(self) { fIsEnabled = enabled; - + // Warning: This won't work if the parent menu is disabled. // See [CMenu syncFromJava]. We still need to call it here so // the NSMenuItem itself gets properly updated. @@ -183,7 +225,7 @@ JNF_COCOA_EXIT(env); } - (BOOL)isEnabled { - + BOOL enabled = NO; @synchronized(self) { enabled = fIsEnabled; @@ -193,7 +235,7 @@ JNF_COCOA_EXIT(env); - (void)setJavaState:(BOOL)newState { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setState:(newState ? NSOnState : NSOffState)]; }]; @@ -207,7 +249,7 @@ JNF_COCOA_EXIT(env); - (void)dealloc { [fMenuItem release]; fMenuItem = nil; - + [super dealloc]; } @@ -240,7 +282,7 @@ JNF_COCOA_EXIT(env); /** Convert a Java keycode for SetMenuItemCmd */ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) { unichar macKey = 0; - + if ((awtKey >= java_awt_event_KeyEvent_VK_0 && awtKey <= java_awt_event_KeyEvent_VK_9) || (awtKey >= java_awt_event_KeyEvent_VK_A && awtKey <= java_awt_event_KeyEvent_VK_Z)) { @@ -255,68 +297,68 @@ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) { } else { // Special characters switch (awtKey) { - case java_awt_event_KeyEvent_VK_BACK_QUOTE : macKey = '`'; break; - case java_awt_event_KeyEvent_VK_QUOTE : macKey = '\''; break; - - case java_awt_event_KeyEvent_VK_ESCAPE : macKey = 0x1B; break; - case java_awt_event_KeyEvent_VK_SPACE : macKey = ' '; break; - case java_awt_event_KeyEvent_VK_PAGE_UP : macKey = NSPageUpFunctionKey; break; - case java_awt_event_KeyEvent_VK_PAGE_DOWN : macKey = NSPageDownFunctionKey; break; - case java_awt_event_KeyEvent_VK_END : macKey = NSEndFunctionKey; break; - case java_awt_event_KeyEvent_VK_HOME : macKey = NSHomeFunctionKey; break; - - case java_awt_event_KeyEvent_VK_LEFT : macKey = NSLeftArrowFunctionKey; break; - case java_awt_event_KeyEvent_VK_UP : macKey = NSUpArrowFunctionKey; break; - case java_awt_event_KeyEvent_VK_RIGHT : macKey = NSRightArrowFunctionKey; break; - case java_awt_event_KeyEvent_VK_DOWN : macKey = NSDownArrowFunctionKey; break; - - case java_awt_event_KeyEvent_VK_COMMA : macKey = ','; break; - - // Mac OS doesn't distinguish between the two '-' keys... - case java_awt_event_KeyEvent_VK_MINUS : - case java_awt_event_KeyEvent_VK_SUBTRACT : macKey = '-'; break; - - // or the two '.' keys... - case java_awt_event_KeyEvent_VK_DECIMAL : - case java_awt_event_KeyEvent_VK_PERIOD : macKey = '.'; break; - - // or the two '/' keys. - case java_awt_event_KeyEvent_VK_DIVIDE : - case java_awt_event_KeyEvent_VK_SLASH : macKey = '/'; break; - - case java_awt_event_KeyEvent_VK_SEMICOLON : macKey = ';'; break; - case java_awt_event_KeyEvent_VK_EQUALS : macKey = '='; break; - - case java_awt_event_KeyEvent_VK_OPEN_BRACKET : macKey = '['; break; - case java_awt_event_KeyEvent_VK_BACK_SLASH : macKey = '\\'; break; - case java_awt_event_KeyEvent_VK_CLOSE_BRACKET : macKey = ']'; break; - - case java_awt_event_KeyEvent_VK_MULTIPLY : macKey = '*'; break; - case java_awt_event_KeyEvent_VK_ADD : macKey = '+'; break; - - case java_awt_event_KeyEvent_VK_HELP : macKey = NSHelpFunctionKey; break; - case java_awt_event_KeyEvent_VK_TAB : macKey = NSTabCharacter; break; - case java_awt_event_KeyEvent_VK_ENTER : macKey = NSNewlineCharacter; break; - case java_awt_event_KeyEvent_VK_BACK_SPACE : macKey = NSBackspaceCharacter; break; - case java_awt_event_KeyEvent_VK_DELETE : macKey = NSDeleteCharacter; break; - case java_awt_event_KeyEvent_VK_CLEAR : macKey = NSClearDisplayFunctionKey; break; - case java_awt_event_KeyEvent_VK_AMPERSAND : macKey = '&'; break; - case java_awt_event_KeyEvent_VK_ASTERISK : macKey = '*'; break; - case java_awt_event_KeyEvent_VK_QUOTEDBL : macKey = '\"'; break; - case java_awt_event_KeyEvent_VK_LESS : macKey = '<'; break; - case java_awt_event_KeyEvent_VK_GREATER : macKey = '>'; break; - case java_awt_event_KeyEvent_VK_BRACELEFT : macKey = '{'; break; - case java_awt_event_KeyEvent_VK_BRACERIGHT : macKey = '}'; break; - case java_awt_event_KeyEvent_VK_AT : macKey = '@'; break; - case java_awt_event_KeyEvent_VK_COLON : macKey = ':'; break; - case java_awt_event_KeyEvent_VK_CIRCUMFLEX : macKey = '^'; break; - case java_awt_event_KeyEvent_VK_DOLLAR : macKey = '$'; break; - case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break; - case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break; - case java_awt_event_KeyEvent_VK_NUMBER_SIGN : macKey = '#'; break; - case java_awt_event_KeyEvent_VK_PLUS : macKey = '+'; break; - case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break; - case java_awt_event_KeyEvent_VK_UNDERSCORE : macKey = '_'; break; + case java_awt_event_KeyEvent_VK_BACK_QUOTE : macKey = '`'; break; + case java_awt_event_KeyEvent_VK_QUOTE : macKey = '\''; break; + + case java_awt_event_KeyEvent_VK_ESCAPE : macKey = 0x1B; break; + case java_awt_event_KeyEvent_VK_SPACE : macKey = ' '; break; + case java_awt_event_KeyEvent_VK_PAGE_UP : macKey = NSPageUpFunctionKey; break; + case java_awt_event_KeyEvent_VK_PAGE_DOWN : macKey = NSPageDownFunctionKey; break; + case java_awt_event_KeyEvent_VK_END : macKey = NSEndFunctionKey; break; + case java_awt_event_KeyEvent_VK_HOME : macKey = NSHomeFunctionKey; break; + + case java_awt_event_KeyEvent_VK_LEFT : macKey = NSLeftArrowFunctionKey; break; + case java_awt_event_KeyEvent_VK_UP : macKey = NSUpArrowFunctionKey; break; + case java_awt_event_KeyEvent_VK_RIGHT : macKey = NSRightArrowFunctionKey; break; + case java_awt_event_KeyEvent_VK_DOWN : macKey = NSDownArrowFunctionKey; break; + + case java_awt_event_KeyEvent_VK_COMMA : macKey = ','; break; + + // Mac OS doesn't distinguish between the two '-' keys... + case java_awt_event_KeyEvent_VK_MINUS : + case java_awt_event_KeyEvent_VK_SUBTRACT : macKey = '-'; break; + + // or the two '.' keys... + case java_awt_event_KeyEvent_VK_DECIMAL : + case java_awt_event_KeyEvent_VK_PERIOD : macKey = '.'; break; + + // or the two '/' keys. + case java_awt_event_KeyEvent_VK_DIVIDE : + case java_awt_event_KeyEvent_VK_SLASH : macKey = '/'; break; + + case java_awt_event_KeyEvent_VK_SEMICOLON : macKey = ';'; break; + case java_awt_event_KeyEvent_VK_EQUALS : macKey = '='; break; + + case java_awt_event_KeyEvent_VK_OPEN_BRACKET : macKey = '['; break; + case java_awt_event_KeyEvent_VK_BACK_SLASH : macKey = '\\'; break; + case java_awt_event_KeyEvent_VK_CLOSE_BRACKET : macKey = ']'; break; + + case java_awt_event_KeyEvent_VK_MULTIPLY : macKey = '*'; break; + case java_awt_event_KeyEvent_VK_ADD : macKey = '+'; break; + + case java_awt_event_KeyEvent_VK_HELP : macKey = NSHelpFunctionKey; break; + case java_awt_event_KeyEvent_VK_TAB : macKey = NSTabCharacter; break; + case java_awt_event_KeyEvent_VK_ENTER : macKey = NSNewlineCharacter; break; + case java_awt_event_KeyEvent_VK_BACK_SPACE : macKey = NSBackspaceCharacter; break; + case java_awt_event_KeyEvent_VK_DELETE : macKey = NSDeleteCharacter; break; + case java_awt_event_KeyEvent_VK_CLEAR : macKey = NSClearDisplayFunctionKey; break; + case java_awt_event_KeyEvent_VK_AMPERSAND : macKey = '&'; break; + case java_awt_event_KeyEvent_VK_ASTERISK : macKey = '*'; break; + case java_awt_event_KeyEvent_VK_QUOTEDBL : macKey = '\"'; break; + case java_awt_event_KeyEvent_VK_LESS : macKey = '<'; break; + case java_awt_event_KeyEvent_VK_GREATER : macKey = '>'; break; + case java_awt_event_KeyEvent_VK_BRACELEFT : macKey = '{'; break; + case java_awt_event_KeyEvent_VK_BRACERIGHT : macKey = '}'; break; + case java_awt_event_KeyEvent_VK_AT : macKey = '@'; break; + case java_awt_event_KeyEvent_VK_COLON : macKey = ':'; break; + case java_awt_event_KeyEvent_VK_CIRCUMFLEX : macKey = '^'; break; + case java_awt_event_KeyEvent_VK_DOLLAR : macKey = '$'; break; + case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break; + case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break; + case java_awt_event_KeyEvent_VK_NUMBER_SIGN : macKey = '#'; break; + case java_awt_event_KeyEvent_VK_PLUS : macKey = '+'; break; + case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break; + case java_awt_event_KeyEvent_VK_UNDERSCORE : macKey = '_'; break; } } return macKey; @@ -330,27 +372,27 @@ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) { JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetLabel (JNIEnv *env, jobject peer, - jlong menuItemObj, jstring label, - jchar shortcutKey, jint shortcutKeyCode, jint mods) + jlong menuItemObj, jstring label, + jchar shortcutKey, jint shortcutKeyCode, jint mods) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); NSString *theLabel = JNFJavaToNSString(env, label); NSString *theKeyEquivalent = nil; unichar macKey = shortcutKey; - + if (macKey == 0) { macKey = AWTKeyToMacShortcut(shortcutKeyCode, (mods & java_awt_event_KeyEvent_SHIFT_MASK) != 0); } - + if (macKey != 0) { unichar equivalent[1] = {macKey}; theKeyEquivalent = [NSString stringWithCharacters:equivalent length:1]; } else { theKeyEquivalent = @""; } - + [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaLabel:theLabel shortcut:theKeyEquivalent modifierMask:mods]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -362,10 +404,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetTooltip (JNIEnv *env, jobject peer, jlong menuItemObj, jstring tooltip) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); NSString *theTooltip = JNFJavaToNSString(env, tooltip); [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaToolTipText:theTooltip]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -377,9 +419,9 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetImage (JNIEnv *env, jobject peer, jlong menuItemObj, jlong image) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaImage:(NSImage*)jlong_to_ptr(image)]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -389,38 +431,38 @@ JNF_COCOA_EXIT(env); */ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeCreate - (JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator) +(JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator) { - + CMenuItem *aCMenuItem = nil; CMenu *parentCMenu = (CMenu *)jlong_to_ptr(parentCMenuObj); -JNF_COCOA_ENTER(env); - + JNF_COCOA_ENTER(env); + jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer); - + NSMutableArray *args = nil; - + // Create a new item.... if (isSeparator == JNI_TRUE) { args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:YES], nil]; } else { args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO], nil]; } - + [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES]; - + aCMenuItem = (CMenuItem *)[args objectAtIndex: 0]; - + if (aCMenuItem == nil) { return 0L; } - + // and add it to the parent item. [parentCMenu addJavaMenuItem: aCMenuItem]; - + // setLabel will be called after creation completes. - -JNF_COCOA_EXIT(env); + + JNF_COCOA_EXIT(env); return ptr_to_jlong(aCMenuItem); } @@ -433,10 +475,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetEnabled (JNIEnv *env, jobject peer, jlong menuItemObj, jboolean enable) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj); [item setJavaEnabled: (enable == JNI_TRUE)]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -448,10 +490,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetState (JNIEnv *env, jobject peer, jlong menuItemObj, jboolean state) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj); [item setJavaState: (state == JNI_TRUE)]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -463,8 +505,8 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetIsCheckbox (JNIEnv *env, jobject peer, jlong menuItemObj) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj); [item setIsCheckbox]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } diff --git a/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java b/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java new file mode 100644 index 00000000000..b591e6bc585 --- /dev/null +++ b/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8139169 + * @summary verifies if TextArea gets input twice due to Apple's Screen Menubar + * @requires (os.family=="mac") + * @library ../../regtesthelpers + * @build Util + * @run main ScreenMenuBarInputTwice + */ +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import static java.awt.event.KeyEvent.VK_COMMA; +import static java.awt.event.KeyEvent.VK_META; +import static java.awt.event.KeyEvent.VK_SHIFT; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + +public class ScreenMenuBarInputTwice { + + public static final String TEST_STRING = "Check string"; + + private static Robot robot; + private static JFrame frame; + private static JPanel content; + private static JTextArea textArea; + private static JMenuBar menuBar; + private static JMenu menu; + private static JMenuItem menuItem; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + createUIWithSeperateMenuBar(); + robot.delay(2000); + shortcutTestCase(); + robot.delay(2000); + cleanUp(); + createUIWithIntegratedMenuBar(); + robot.delay(2000); + menuTestCase(); + robot.delay(2000); + cleanUp(); + } + + private static void createUIWithSeperateMenuBar() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + System.setProperty( + "com.apple.mrj.application.apple.menu.about.name", + "A test frame"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + frame = new JFrame("Text input twice check"); + content = new JPanel(new BorderLayout()); + textArea = new JTextArea(); + content.add(new JScrollPane(textArea, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), + BorderLayout.CENTER); + menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + Action a = new AbstractAction("Insert some text") { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + + textArea.getDocument() + .insertString(0, TEST_STRING, null); + } catch (BadLocationException e) { + frame.dispose(); + throw new RuntimeException("Bad location: ", e); + } + } + }; + KeyStroke keyStroke = KeyStroke.getKeyStroke( + "meta shift COMMA"); + a.putValue(Action.ACCELERATOR_KEY, keyStroke); + textArea.getInputMap().put(keyStroke, "myAction"); + textArea.getActionMap().put("myAction", a); + menu = new JMenu("The Menu"); + menuItem = new JMenuItem(a); + menuItem.setAccelerator((KeyStroke) a.getValue( + Action.ACCELERATOR_KEY)); + menu.add(menuItem); + menuBar.add(menu); + frame.getContentPane().add(content); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setLocationRelativeTo(null); + frame.setSize(500, 500); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void createUIWithIntegratedMenuBar() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + System.setProperty( + "com.apple.mrj.application.apple.menu.about.name", + "A test frame"); + System.setProperty("apple.laf.useScreenMenuBar", "false"); + frame = new JFrame("Text input twice check"); + content = new JPanel(new BorderLayout()); + textArea = new JTextArea(); + content.add(new JScrollPane(textArea, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), + BorderLayout.CENTER); + menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + Action a = new AbstractAction("Insert some text") { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + + textArea.getDocument() + .insertString(0, TEST_STRING, null); + } catch (BadLocationException e) { + frame.dispose(); + throw new RuntimeException("Bad location: ", e); + } + } + }; + KeyStroke keyStroke = KeyStroke.getKeyStroke( + "meta shift COMMA"); + a.putValue(Action.ACCELERATOR_KEY, keyStroke); + textArea.getInputMap().put(keyStroke, "myAction"); + textArea.getActionMap().put("myAction", a); + menu = new JMenu("The Menu"); + menuItem = new JMenuItem(a); + menuItem.setAccelerator((KeyStroke) a.getValue( + Action.ACCELERATOR_KEY)); + menu.add(menuItem); + menuBar.add(menu); + frame.getContentPane().add(content); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void shortcutTestCase() throws Exception { + robot.keyPress(KeyEvent.VK_META); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_COMMA); + robot.keyRelease(VK_COMMA); + robot.keyRelease(VK_SHIFT); + robot.keyRelease(VK_META); + robot.delay(2000); + checkText(textArea.getText()); + } + + private static void menuTestCase() throws Exception { + Point mousePoint; + mousePoint = Util.getCenterPoint(menu); + robot.mouseMove(mousePoint.x, mousePoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.delay(2000); + mousePoint = Util.getCenterPoint(menuItem); + robot.mouseMove(mousePoint.x, mousePoint.y); + robot.delay(2000); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.delay(2000); + checkText(textArea.getText()); + } + + private static void checkText(String text) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (TEST_STRING.equals(text)) { + textArea.setText(""); + } else { + frame.dispose(); + throw new RuntimeException("Failed. " + + " Menu item shortcut invoked twice"); + } + } + }); + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } +} From 946e0bc9cc01c228cb3c9a6b86aa145904788b04 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 10 Dec 2015 16:09:42 +0300 Subject: [PATCH 029/151] 8040139: Test closed/javax/print/attribute/Services_getDocFl.java fails with NullpointerException Reviewed-by: jdv, prr --- .../classes/sun/print/IPPPrintService.java | 5 +- .../print/attribute/Services_getDocFl.java | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/print/attribute/Services_getDocFl.java diff --git a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java index 7782d543219..9587067a750 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java @@ -926,7 +926,10 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { return copyflavors; } } - return null; + DocFlavor[] flavor = new DocFlavor[2]; + flavor[0] = DocFlavor.SERVICE_FORMATTED.PAGEABLE; + flavor[1] = DocFlavor.SERVICE_FORMATTED.PRINTABLE; + return flavor; } diff --git a/jdk/test/javax/print/attribute/Services_getDocFl.java b/jdk/test/javax/print/attribute/Services_getDocFl.java new file mode 100644 index 00000000000..e3f0a850e3f --- /dev/null +++ b/jdk/test/javax/print/attribute/Services_getDocFl.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +import javax.print.DocFlavor; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.attribute.HashPrintRequestAttributeSet; + +/* + * @test + * @bug 4901243 8040139 + * @summary JPG, GIF, and PNG DocFlavors (URL) should be supported if Postscript is supported. + * @run main Services_getDocFl +*/ + + +public class Services_getDocFl { + public static void main (String [] args) { + + HashPrintRequestAttributeSet prSet = null; + boolean psSupported = false, + pngImagesSupported = false, + gifImagesSupported = false, + jpgImagesSupported = false; + String mimeType; + + PrintService[] serv = PrintServiceLookup.lookupPrintServices(null, null); + if (serv.length==0) { + System.out.println("no PrintService found"); + } else { + System.out.println("number of Services "+serv.length); + } + + + for (int i = 0; i Date: Thu, 10 Dec 2015 12:16:29 -0600 Subject: [PATCH 030/151] 8071334: Investigate JAB changes required to support the version string change Remove use of java.version property; no longer needed Reviewed-by: van, alexsch --- .../accessibility/util/AWTEventMonitor.java | 20 ++----------------- .../accessibility/internal/AccessBridge.java | 10 ++-------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java index 7b0f8c29e06..257bbb72953 100644 --- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java @@ -48,8 +48,6 @@ import sun.awt.AWTPermissions; @jdk.Exported public class AWTEventMonitor { - static private boolean runningOnJDK1_4 = false; - /** * The current component with keyboard focus. * @@ -638,15 +636,9 @@ public class AWTEventMonitor { * @see AWTEventMonitor */ public AWTEventsListener() { - String version = System.getProperty("java.version"); - if (version != null) { - runningOnJDK1_4 = (version.compareTo("1.4") >= 0); - } initializeIntrospection(); installListeners(); - if (runningOnJDK1_4) { - MenuSelectionManager.defaultManager().addChangeListener(this); - } + MenuSelectionManager.defaultManager().addChangeListener(this); EventQueueMonitor.addTopLevelWindowListener(this); } @@ -848,15 +840,7 @@ public class AWTEventMonitor { case EventID.FOCUS: c.removeFocusListener(this); c.addFocusListener(this); - - if (runningOnJDK1_4) { - processFocusGained(); - - } else { // not runningOnJDK1_4 - if ((c != componentWithFocus_private) && c.hasFocus()) { - componentWithFocus_private = c; - } - } + processFocusGained(); break; case EventID.ITEM: diff --git a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java index ee1a63f5ec9..47832a4455b 100644 --- a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java @@ -140,10 +140,6 @@ final public class AccessBridge { // initialize AccessibleRole map initAccessibleRoleMap(); - // determine which version of the JDK is running - String version = getJavaVersionProperty(); - debugString("JDK version = "+version); - // initialize the methods that map HWNDs and Java top-level // windows initHWNDcalls(); @@ -215,9 +211,7 @@ final public class AccessBridge { } catch (Exception e) {} /* - Build the extendedVirtualNameSearchRoles array list. I chose this method - because some of the Accessible Roles that need to be added to it are not - available in all versions of the J2SE that we want to support. + Build the extendedVirtualNameSearchRoles array list. */ extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX); try { @@ -5919,7 +5913,7 @@ final public class AccessBridge { */ AccessibleRole.UNKNOWN, - // These roles are only available in JDK 1.4 + // These roles are available since JDK 1.4 /** * A STATUS_BAR is an simple component that can contain From c588dd42dd368d2ef8b6350ec6766c5837c3b39a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 10 Dec 2015 12:51:08 -0800 Subject: [PATCH 031/151] 8144858: HBShaper.c does not compiler with VS2010 Reviewed-by: serb, simonis --- .../share/native/libfontmanager/HBShaper.c | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c index 422575cb165..00c6ee1fa44 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c +++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c @@ -80,15 +80,18 @@ int storeGVData(JNIEnv* env, float scale = 1.0f/64.0f; unsigned int* glyphs; float* positions; + int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv; + unsigned int* indices; + jarray glyphArray, posArray, inxArray; if (!init_JNI_IDs(env)) { return 0; } - int initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID); - jarray glyphArray = + initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID); + glyphArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID); - jarray posArray = + posArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID); if (glyphArray == NULL || posArray == NULL) @@ -101,9 +104,9 @@ int storeGVData(JNIEnv* env, // and re-invokes layout. I suppose this is expected to be rare // because at least in a single threaded case there should be // re-use of the same container, but it is a little wasteful/distateful. - int glyphArrayLen = (*env)->GetArrayLength(env, glyphArray); - int posArrayLen = (*env)->GetArrayLength(env, posArray); - int maxGlyphs = glyphCount + initialCount; + glyphArrayLen = (*env)->GetArrayLength(env, glyphArray); + posArrayLen = (*env)->GetArrayLength(env, posArray); + maxGlyphs = glyphCount + initialCount; if ((maxGlyphs > glyphArrayLen) || (maxGlyphs * 2 + 2 > posArrayLen)) { @@ -125,7 +128,7 @@ int storeGVData(JNIEnv* env, x += glyphPos[i].x_advance * scale; y += glyphPos[i].y_advance * scale; } - int storeadv = initialCount+glyphCount; + storeadv = initialCount+glyphCount; // The final slot in the positions array is important // because when the GlyphVector is created from this // data it determines the overall advance of the glyphvector @@ -138,11 +141,10 @@ int storeGVData(JNIEnv* env, (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0); (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0); putFloat(env, startPt,positions[(storeadv*2)],positions[(storeadv*2)+1] ); - jarray inxArray = + inxArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID); - unsigned int* indices = + indices = (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL); - int prevCluster = -1; for (i = 0; i < glyphCount; i++) { int cluster = glyphInfo[i].cluster; if (direction == HB_DIRECTION_LTR) { From bb10c3f0de78a4672b09296c90d3e54fe5fd22ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 10 Dec 2015 15:45:18 -0800 Subject: [PATCH 032/151] 8144446: Automate the Marlin crash test Reviewed-by: prr, flar --- .../classes/sun/java2d/marlin/Renderer.java | 7 +++ jdk/test/sun/java2d/marlin/CrashTest.java | 59 ++++++++++--------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java index d4aa005eadb..f59785cd92f 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java @@ -629,6 +629,13 @@ final class Renderer implements PathConsumer2D, MarlinConst { } if (edgeMinY != Float.POSITIVE_INFINITY) { + // if context is maked as DIRTY: + if (rdrCtx.dirty) { + // may happen if an exception if thrown in the pipeline processing: + // clear completely buckets arrays: + buckets_minY = 0; + buckets_maxY = boundsMaxY - boundsMinY; + } // clear used part if (edgeBuckets == edgeBuckets_initial) { // fill only used part diff --git a/jdk/test/sun/java2d/marlin/CrashTest.java b/jdk/test/sun/java2d/marlin/CrashTest.java index b5f760a65e3..b5283fdf332 100644 --- a/jdk/test/sun/java2d/marlin/CrashTest.java +++ b/jdk/test/sun/java2d/marlin/CrashTest.java @@ -31,31 +31,44 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; -import sun.java2d.pipe.RenderingEngine; /** - * Simple crash rendering test using huge GeneralPaths with marlin renderer - * - * run it with large heap (2g): - * java -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine marlin.CrashTest - * - * @author bourgesl - */ + * @test + * @summary Simple crash rendering test using huge GeneralPaths with the Marlin renderer + * @run main/othervm -mx512m CrashTest + * @ignore tests that take a long time and consumes 5Gb memory + * @run main/othervm -ms4g -mx4g CrashTest -slow +*/ public class CrashTest { static final boolean SAVE_IMAGE = false; static boolean USE_ROUND_CAPS_AND_JOINS = true; public static void main(String[] args) { + boolean runSlowTests = (args.length != 0 && "-slow".equals(args[0])); + + // First display which renderer is tested: + System.setProperty("sun.java2d.renderer.verbose", "true"); + // try insane image sizes: // subpixel coords may overflow: -// testHugeImage((Integer.MAX_VALUE >> 3) + 1, 6); + // check MAX_VALUE / (8 * 2); overflow may happen due to orientation flag + // But as it is impossible to allocate an image larger than 2Gb (byte) then + // it is also impossible to have rowAAChunk larger than 2Gb ! + + // Disabled test as it consumes 4GB heap + offheap (2Gb) ie > 6Gb ! + if (runSlowTests) { + testHugeImage((Integer.MAX_VALUE >> 4) - 100, 16); + } + // larger than 23 bits: (RLE) testHugeImage(8388608 + 1, 10); - test(0.1f, false, 0); - test(0.1f, true, 7f); + if (runSlowTests) { + test(0.1f, false, 0); + test(0.1f, true, 7f); + } // Exceed 2Gb OffHeap buffer for edges: try { @@ -67,17 +80,15 @@ public class CrashTest { if (th instanceof ArrayIndexOutOfBoundsException) { System.out.println("ArrayIndexOutOfBoundsException expected."); } else { - System.out.println("Exception occured:"); - th.printStackTrace(); + throw new RuntimeException("Unexpected exception", th); } } - } private static void test(final float lineStroke, final boolean useDashes, final float dashMinLen) - throws ArrayIndexOutOfBoundsException + throws ArrayIndexOutOfBoundsException { System.out.println("---\n" + "test: " + "lineStroke=" + lineStroke @@ -85,9 +96,6 @@ public class CrashTest { +", dashMinLen=" + dashMinLen ); - final String renderer = RenderingEngine.getInstance().getClass().getSimpleName(); - System.out.println("Testing renderer = " + renderer); - final BasicStroke stroke = createStroke(lineStroke, useDashes, dashMinLen); // TODO: test Dasher.firstSegmentsBuffer resizing ? @@ -135,7 +143,7 @@ public class CrashTest { if (SAVE_IMAGE) { try { - final File file = new File("CrashTest-" + renderer + "-dash-" + useDashes + ".bmp"); + final File file = new File("CrashTest-dash-" + useDashes + ".bmp"); System.out.println("Writing file: " + file.getAbsolutePath()); ImageIO.write(image, "BMP", file); @@ -150,15 +158,10 @@ public class CrashTest { } private static void testHugeImage(final int width, final int height) - throws ArrayIndexOutOfBoundsException + throws ArrayIndexOutOfBoundsException { System.out.println("---\n" + "testHugeImage: " - + "width=" + width - + ", height=" + height - ); - - final String renderer = RenderingEngine.getInstance().getClass().getSimpleName(); - System.out.println("Testing renderer = " + renderer); + + "width=" + width + ", height=" + height); final BasicStroke stroke = createStroke(2.5f, false, 0); @@ -195,8 +198,8 @@ public class CrashTest { if (SAVE_IMAGE) { try { - final File file = new File("CrashTest-" + renderer + - "-huge-" + width + "x" +height + ".bmp"); + final File file = new File("CrashTest-huge-" + + width + "x" +height + ".bmp"); System.out.println("Writing file: " + file.getAbsolutePath()); ImageIO.write(image, "BMP", file); From 80222f5b67383332c7c7ba63eaa6f40bbc30181f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 10 Dec 2015 15:52:14 -0800 Subject: [PATCH 033/151] 8144445: Maximum size checking in Marlin ArrayCache utility methods is not optimal Reviewed-by: prr, flar --- .../classes/sun/java2d/marlin/ArrayCache.java | 38 +++-- .../classes/sun/java2d/marlin/Stroker.java | 5 +- .../sun/java2d/marlin/ArrayCacheSizeTest.java | 131 ++++++++++++++++++ 3 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java index bc4bc54d0d5..e518c4d2261 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java @@ -166,18 +166,31 @@ public final class ArrayCache implements MarlinConst { * @return new array size */ public static int getNewSize(final int curSize, final int needSize) { + // check if needSize is negative or integer overflow: + if (needSize < 0) { + // hard overflow failure - we can't even accommodate + // new items without overflowing + throw new ArrayIndexOutOfBoundsException( + "array exceeds maximum capacity !"); + } + assert curSize >= 0; final int initial = (curSize & MASK_CLR_1); int size; if (initial > THRESHOLD_ARRAY_SIZE) { size = initial + (initial >> 1); // x(3/2) } else { - size = (initial) << 1; // x2 + size = (initial << 1); // x2 } // ensure the new size is >= needed size: if (size < needSize) { - // align to 4096: + // align to 4096 (may overflow): size = ((needSize >> 12) + 1) << 12; } + // check integer overflow: + if (size < 0) { + // resize to maximum capacity: + size = Integer.MAX_VALUE; + } return size; } @@ -188,26 +201,29 @@ public final class ArrayCache implements MarlinConst { * @return new array size */ public static long getNewLargeSize(final long curSize, final long needSize) { + // check if needSize is negative or integer overflow: + if ((needSize >> 31L) != 0L) { + // hard overflow failure - we can't even accommodate + // new items without overflowing + throw new ArrayIndexOutOfBoundsException( + "array exceeds maximum capacity !"); + } + assert curSize >= 0L; long size; if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) { size = curSize + (curSize >> 2L); // x(5/4) } else if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) { size = curSize + (curSize >> 1L); // x(3/2) } else { - size = curSize << 1L; // x2 + size = (curSize << 1L); // x2 } // ensure the new size is >= needed size: if (size < needSize) { // align to 4096: - size = ((needSize >> 12) + 1) << 12; + size = ((needSize >> 12L) + 1L) << 12L; } - if (size >= Integer.MAX_VALUE) { - if (curSize >= Integer.MAX_VALUE) { - // hard overflow failure - we can't even accommodate - // new items without overflowing - throw new ArrayIndexOutOfBoundsException( - "array exceeds maximum capacity !"); - } + // check integer overflow: + if (size > Integer.MAX_VALUE) { // resize to maximum capacity: size = Integer.MAX_VALUE; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java index 76c93494d57..1aa48411f04 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java @@ -1265,14 +1265,15 @@ final class Stroker implements PathConsumer2D, MarlinConst { } private void ensureSpace(final int n) { - if (end + n > curves.length) { + // use substraction to avoid integer overflow: + if (curves.length - end < n) { if (doStats) { RendererContext.stats.stat_array_stroker_polystack_curves .add(end + n); } curves = rdrCtx.widenDirtyFloatArray(curves, end, end + n); } - if (numCurves + 1 > curveTypes.length) { + if (curveTypes.length <= numCurves) { if (doStats) { RendererContext.stats.stat_array_stroker_polystack_curveTypes .add(numCurves + 1); diff --git a/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java b/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java new file mode 100644 index 00000000000..8c40fe4cfae --- /dev/null +++ b/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +import sun.java2d.marlin.ArrayCache; + +/** + * @test + * @bug 8144445 + * @summary Check the ArrayCache getNewLargeSize() method + * @run main ArrayCacheSizeTest + */ +public class ArrayCacheSizeTest { + + public static void main(String[] args) { + testNewSize(); + testNewLargeSize(); + } + + private static void testNewSize() { + testNewSize(0, 1); + testNewSize(0, 100000); + + testNewSize(4096, 4097); + testNewSize(4096 * 16, 4096 * 16 + 1); + + testNewSize(4096 * 4096 * 4, 4096 * 4096 * 4 + 1); + + testNewSize(4096 * 4096 * 4, Integer.MAX_VALUE); + + testNewSize(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE); + + testNewSizeExpectAIOB(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE + 1); + testNewSizeExpectAIOB(1, -1); + testNewSizeExpectAIOB(Integer.MAX_VALUE, -1); + } + + private static void testNewSizeExpectAIOB(final int curSize, + final int needSize) { + try { + testNewSize(curSize, needSize); + throw new RuntimeException("ArrayIndexOutOfBoundsException not thrown"); + } catch (ArrayIndexOutOfBoundsException aiobe) { + System.out.println("ArrayIndexOutOfBoundsException expected."); + } catch (RuntimeException re) { + throw re; + } catch (Throwable th) { + throw new RuntimeException("Unexpected exception", th); + } + } + + private static void testNewSize(final int curSize, + final int needSize) { + + int size = ArrayCache.getNewSize(curSize, needSize); + + System.out.println("getNewSize(" + curSize + ", " + needSize + + ") = " + size); + + if (size < 0 || size < needSize) { + throw new IllegalStateException("Invalid getNewSize(" + + curSize + ", " + needSize + ") = " + size + " !"); + } + } + + private static void testNewLargeSize() { + testNewLargeSize(0, 1); + testNewLargeSize(0, 100000); + + testNewLargeSize(4096, 4097); + testNewLargeSize(4096 * 16, 4096 * 16 + 1); + + testNewLargeSize(4096 * 4096 * 4, 4096 * 4096 * 4 + 1); + + testNewLargeSize(4096 * 4096 * 4, Integer.MAX_VALUE); + + testNewLargeSize(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE); + + testNewLargeSizeExpectAIOB(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE + 1L); + testNewLargeSizeExpectAIOB(1, -1L); + testNewLargeSizeExpectAIOB(Integer.MAX_VALUE, -1L); + } + + private static void testNewLargeSizeExpectAIOB(final long curSize, + final long needSize) { + try { + testNewLargeSize(curSize, needSize); + throw new RuntimeException("ArrayIndexOutOfBoundsException not thrown"); + } catch (ArrayIndexOutOfBoundsException aiobe) { + System.out.println("ArrayIndexOutOfBoundsException expected."); + } catch (RuntimeException re) { + throw re; + } catch (Throwable th) { + throw new RuntimeException("Unexpected exception", th); + } + } + + private static void testNewLargeSize(final long curSize, + final long needSize) { + + long size = ArrayCache.getNewLargeSize(curSize, needSize); + + System.out.println("getNewLargeSize(" + curSize + ", " + needSize + + ") = " + size); + + if (size < 0 || size < needSize || size > Integer.MAX_VALUE) { + throw new IllegalStateException("Invalid getNewLargeSize(" + + curSize + ", " + needSize + ") = " + size + " !"); + } + } + +} From 583937011af76bd244566791f598991fbd7cd995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 10 Dec 2015 15:58:01 -0800 Subject: [PATCH 034/151] 8144654: Improve Marlin logging Reviewed-by: prr, flar --- .../sun/java2d/marlin/ByteArrayCache.java | 4 ++-- .../sun/java2d/marlin/FloatArrayCache.java | 4 ++-- .../sun/java2d/marlin/IntArrayCache.java | 4 ++-- .../sun/java2d/marlin/MarlinConst.java | 9 ++++---- .../sun/java2d/marlin/MarlinProperties.java | 4 ++++ .../sun/java2d/marlin/MarlinUtils.java | 22 ++++--------------- .../sun/java2d/marlin/RendererContext.java | 22 +++++++------------ 7 files changed, 27 insertions(+), 42 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java index cd6ebee89e8..226a3d2e30d 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java @@ -74,7 +74,7 @@ final class ByteArrayCache implements MarlinConst { void putDirtyArray(final byte[] array, final int length) { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } @@ -98,7 +98,7 @@ final class ByteArrayCache implements MarlinConst { { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java index a068ad80fbc..06d7f351e28 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java @@ -75,7 +75,7 @@ final class FloatArrayCache implements MarlinConst { void putDirtyArray(final float[] array, final int length) { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } @@ -99,7 +99,7 @@ final class FloatArrayCache implements MarlinConst { { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java index ccd239cb534..11c5aae84f6 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java @@ -74,7 +74,7 @@ final class IntArrayCache implements MarlinConst { void putDirtyArray(final int[] array, final int length) { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } @@ -98,7 +98,7 @@ final class IntArrayCache implements MarlinConst { { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java index e799504318d..72993ebfd7c 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java @@ -30,8 +30,8 @@ package sun.java2d.marlin; */ interface MarlinConst { // enable Logs (logger or stdout) - static final boolean enableLogs = false; - // enable Logger + static final boolean enableLogs = MarlinProperties.isLoggingEnabled(); + // use Logger instead of stdout static final boolean useLogger = enableLogs && MarlinProperties.isUseLogger(); // log new RendererContext @@ -47,9 +47,10 @@ interface MarlinConst { static final boolean doStats = enableLogs && MarlinProperties.isDoStats(); // do monitors // disabled to reduce byte-code size a bit... - static final boolean doMonitors = enableLogs && false; // MarlinProperties.isDoMonitors(); + static final boolean doMonitors = false; +// static final boolean doMonitors = enableLogs && MarlinProperties.isDoMonitors(); // do checks - static final boolean doChecks = false; // MarlinProperties.isDoChecks(); + static final boolean doChecks = enableLogs && MarlinProperties.isDoChecks(); // do AA range checks: disable when algorithm / code is stable static final boolean DO_AA_RANGE_CHECK = false; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java index 002f16d9d5b..bbee15a13fb 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java @@ -136,6 +136,10 @@ public final class MarlinProperties { // logging parameters + public static boolean isLoggingEnabled() { + return getBoolean("sun.java2d.renderer.log", "false"); + } + public static boolean isUseLogger() { return getBoolean("sun.java2d.renderer.useLogger", "false"); } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java index d218d06f545..aeeacca57bd 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java @@ -27,12 +27,12 @@ package sun.java2d.marlin; public final class MarlinUtils { - // TODO: use sun.util.logging.PlatformLogger once in JDK9 - private static final java.util.logging.Logger log; + // Marlin logger + private static final sun.util.logging.PlatformLogger log; static { if (MarlinConst.useLogger) { - log = java.util.logging.Logger.getLogger("sun.java2d.marlin"); + log = sun.util.logging.PlatformLogger.getLogger("sun.java2d.marlin"); } else { log = null; } @@ -53,25 +53,11 @@ public final class MarlinUtils { public static void logException(final String msg, final Throwable th) { if (MarlinConst.useLogger) { -// log.warning(msg, th); - log.log(java.util.logging.Level.WARNING, msg, th); + log.warning(msg, th); } else if (MarlinConst.enableLogs) { System.out.print("WARNING: "); System.out.println(msg); th.printStackTrace(System.err); } } - - // Returns the caller's class and method's name; best effort - // if cannot infer, return the logger's name. - static String getCallerInfo(String className) { - String sourceClassName = null; - String sourceMethodName = null; - - if (sourceClassName != null) { - return sourceClassName + " " + sourceMethodName; - } else { - return "unknown"; - } - } } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java index 7af675b16b7..a767651f5d5 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java @@ -31,7 +31,6 @@ import java.lang.ref.WeakReference; import java.util.concurrent.atomic.AtomicInteger; import static sun.java2d.marlin.ArrayCache.*; import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator; -import static sun.java2d.marlin.MarlinUtils.getCallerInfo; import static sun.java2d.marlin.MarlinUtils.logInfo; /** @@ -39,7 +38,6 @@ import static sun.java2d.marlin.MarlinUtils.logInfo; */ final class RendererContext implements MarlinConst { - private static final String className = RendererContext.class.getName(); // RendererContext creation counter private static final AtomicInteger contextCount = new AtomicInteger(1); // RendererContext statistics @@ -214,8 +212,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getDirtyByteArray[oversize]: length=\t" + length - + "\tfrom=\t" + getCallerInfo(className)); + logInfo("getDirtyByteArray[oversize]: length=\t" + length); } return new byte[length]; @@ -254,7 +251,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } @@ -275,8 +272,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getIntArray[oversize]: length=\t" + length + "\tfrom=\t" - + getCallerInfo(className)); + logInfo("getIntArray[oversize]: length=\t" + length); } return new int[length]; @@ -306,7 +302,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenIntArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } @@ -338,8 +334,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getDirtyIntArray[oversize]: length=\t" + length - + "\tfrom=\t" + getCallerInfo(className)); + logInfo("getDirtyIntArray[oversize]: length=\t" + length); } return new int[length]; @@ -369,7 +364,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } @@ -399,8 +394,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getDirtyFloatArray[oversize]: length=\t" + length - + "\tfrom=\t" + getCallerInfo(className)); + logInfo("getDirtyFloatArray[oversize]: length=\t" + length); } return new float[length]; @@ -430,7 +424,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } From b831ed3c8b030fb26855b4df9046ba3a1b9ddfa3 Mon Sep 17 00:00:00 2001 From: Naveen Kumar Date: Tue, 15 Dec 2015 16:42:30 +0900 Subject: [PATCH 035/151] 8139572: SimpleDateFormat parse month stand-alone format bug Reviewed-by: okutsu --- .../classes/java/text/SimpleDateFormat.java | 15 +++ .../text/Format/DateFormat/Bug8139572.java | 120 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 jdk/test/java/text/Format/DateFormat/Bug8139572.java diff --git a/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java b/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java index 488e43635b6..bced263c072 100644 --- a/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -1856,6 +1856,7 @@ public class SimpleDateFormat extends DateFormat { if (patternCharIndex == PATTERN_HOUR_OF_DAY1 || patternCharIndex == PATTERN_HOUR1 || (patternCharIndex == PATTERN_MONTH && count <= 2) || + (patternCharIndex == PATTERN_MONTH_STANDALONE && count <= 2) || patternCharIndex == PATTERN_YEAR || patternCharIndex == PATTERN_WEEK_YEAR) { // It would be good to unify this with the obeyCount logic below, @@ -1976,6 +1977,20 @@ public class SimpleDateFormat extends DateFormat { } break parsing; + case PATTERN_MONTH_STANDALONE: // 'L' + if (count <= 2) { + // Don't want to parse the month if it is a string + // while pattern uses numeric style: L or LL + //[we computed 'value' above.] + calb.set(Calendar.MONTH, value - 1); + return pos.index; + } + Map maps = getDisplayNamesMap(field, locale); + if ((index = matchString(text, start, field, maps, calb)) > 0) { + return index; + } + break parsing; + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59 if (!isLenient()) { // Validate the hour value in non-lenient diff --git a/jdk/test/java/text/Format/DateFormat/Bug8139572.java b/jdk/test/java/text/Format/DateFormat/Bug8139572.java new file mode 100644 index 00000000000..d55196b3a23 --- /dev/null +++ b/jdk/test/java/text/Format/DateFormat/Bug8139572.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8139572 + * @summary SimpleDateFormat parse month stand-alone format bug + * @compile -encoding utf-8 Bug8139572.java + * @run main Bug8139572 + */ +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; + +public class Bug8139572 { + + private static final Locale RUSSIAN = new Locale("ru"); + private static final Date SEPT12 = new GregorianCalendar(2015, Calendar.SEPTEMBER, 12).getTime(); + + private static final String[] PATTERNS = { + "L", + "dd L", + "dd L yy", + "dd L yyyy", + "LL", + "dd LL", + "dd LL yy", + "dd LL yyyy", + "LLL", + "dd LLL", + "dd LLL yy", + "dd LLL yyyy", + "LLLL", + "dd LLLL", + "dd LLLL yy", + "dd LLLL yyyy" + }; + + private static final String[] APPLIED = { + "9", + "12 09", + "12 09 15", + "12 09 2015", + "09", + "12 09", + "12 09 15", + "12 09 2015", + "сентября", + "12 сентября", + "12 сентября 15", + "12 сентября 2015", + "сентября", + "12 сентября", + "12 сентября 15", + "12 сентября 2015" + }; + + private static final String[] EXPECTED = { + "9", + "12 9", + "12 9 15", + "12 9 2015", + "09", + "12 09", + "12 09 15", + "12 09 2015", + "сент.", + "12 сент.", + "12 сент. 15", + "12 сент. 2015", + "сентябрь", + "12 сентябрь", + "12 сентябрь 15", + "12 сентябрь 2015" + }; + + public static void main(String[] args) throws ParseException { + + for (int i = 0; i < PATTERNS.length; i++) { + SimpleDateFormat fmt = new SimpleDateFormat(PATTERNS[i], RUSSIAN); + Date standAloneDate = fmt.parse(APPLIED[i]); + String str = fmt.format(standAloneDate); + if (!EXPECTED[i].equals(str)) { + throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[i] + "'"); + } + } + + SimpleDateFormat fmt = new SimpleDateFormat("", RUSSIAN); + for (int j = 0; j < PATTERNS.length; j++) { + fmt.applyPattern(PATTERNS[j]); + String str = fmt.format(SEPT12); + if (!EXPECTED[j].equals(str)) { + throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[j] + "'"); + } + } + } +} From 61f49a066360e0fef0d674d753b0e8ecd9e009e6 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Tue, 15 Dec 2015 10:11:04 +0000 Subject: [PATCH 036/151] 8145390: Remove sun.misc.Queue and replace usages with standard Collections Reviewed-by: psandoz, mchung, serb --- .../share/classes/sun/misc/Queue.java | 214 ------------------ .../share/classes/sun/applet/AppletPanel.java | 14 +- 2 files changed, 6 insertions(+), 222 deletions(-) delete mode 100644 jdk/src/java.base/share/classes/sun/misc/Queue.java diff --git a/jdk/src/java.base/share/classes/sun/misc/Queue.java b/jdk/src/java.base/share/classes/sun/misc/Queue.java deleted file mode 100644 index 0eed6a08779..00000000000 --- a/jdk/src/java.base/share/classes/sun/misc/Queue.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.util.Enumeration; -import java.util.NoSuchElementException; - -/** - * Queue: implements a simple queue mechanism. Allows for enumeration of the - * elements. - * - * @author Herb Jellinek - */ - -public class Queue { - - int length = 0; - - QueueElement head = null; - QueueElement tail = null; - - public Queue() { - } - - /** - * Enqueue an object. - */ - public synchronized void enqueue(T obj) { - - QueueElement newElt = new QueueElement<>(obj); - - if (head == null) { - head = newElt; - tail = newElt; - length = 1; - } else { - newElt.next = head; - head.prev = newElt; - head = newElt; - length++; - } - notify(); - } - - /** - * Dequeue the oldest object on the queue. Will wait indefinitely. - * - * @return the oldest object on the queue. - * @exception java.lang.InterruptedException if any thread has - * interrupted this thread. - */ - public T dequeue() throws InterruptedException { - return dequeue(0L); - } - - /** - * Dequeue the oldest object on the queue. - * @param timeOut the number of milliseconds to wait for something - * to arrive. - * - * @return the oldest object on the queue. - * @exception java.lang.InterruptedException if any thread has - * interrupted this thread. - */ - public synchronized T dequeue(long timeOut) - throws InterruptedException { - - while (tail == null) { - wait(timeOut); - } - QueueElement elt = tail; - tail = elt.prev; - if (tail == null) { - head = null; - } else { - tail.next = null; - } - length--; - return elt.obj; - } - - /** - * Is the queue empty? - * @return true if the queue is empty. - */ - public synchronized boolean isEmpty() { - return (tail == null); - } - - /** - * Returns an enumeration of the elements in Last-In, First-Out - * order. Use the Enumeration methods on the returned object to - * fetch the elements sequentially. - */ - public final synchronized Enumeration elements() { - return new LIFOQueueEnumerator<>(this); - } - - /** - * Returns an enumeration of the elements in First-In, First-Out - * order. Use the Enumeration methods on the returned object to - * fetch the elements sequentially. - */ - public final synchronized Enumeration reverseElements() { - return new FIFOQueueEnumerator<>(this); - } - - public synchronized void dump(String msg) { - System.err.println(">> "+msg); - System.err.println("["+length+" elt(s); head = "+ - (head == null ? "null" : (head.obj)+"")+ - " tail = "+(tail == null ? "null" : (tail.obj)+"")); - QueueElement cursor = head; - QueueElement last = null; - while (cursor != null) { - System.err.println(" "+cursor); - last = cursor; - cursor = cursor.next; - } - if (last != tail) { - System.err.println(" tail != last: "+tail+", "+last); - } - System.err.println("]"); - } -} - -final class FIFOQueueEnumerator implements Enumeration { - Queue queue; - QueueElement cursor; - - FIFOQueueEnumerator(Queue q) { - queue = q; - cursor = q.tail; - } - - public boolean hasMoreElements() { - return (cursor != null); - } - - public T nextElement() { - synchronized (queue) { - if (cursor != null) { - QueueElement result = cursor; - cursor = cursor.prev; - return result.obj; - } - } - throw new NoSuchElementException("FIFOQueueEnumerator"); - } -} - -final class LIFOQueueEnumerator implements Enumeration { - Queue queue; - QueueElement cursor; - - LIFOQueueEnumerator(Queue q) { - queue = q; - cursor = q.head; - } - - public boolean hasMoreElements() { - return (cursor != null); - } - - public T nextElement() { - synchronized (queue) { - if (cursor != null) { - QueueElement result = cursor; - cursor = cursor.next; - return result.obj; - } - } - throw new NoSuchElementException("LIFOQueueEnumerator"); - } -} - -class QueueElement { - QueueElement next = null; - QueueElement prev = null; - - T obj = null; - - QueueElement(T obj) { - this.obj = obj; - } - - public String toString() { - return "QueueElement[obj="+obj+(prev == null ? " null" : " prev")+ - (next == null ? " null" : " next")+"]"; - } -} diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java index fcefccd9893..a9bacd5c3f2 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java @@ -38,6 +38,7 @@ import java.net.URL; import java.security.*; import java.util.*; import java.util.Locale; +import java.util.concurrent.LinkedBlockingQueue; import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.EmbeddedFrame; @@ -45,7 +46,6 @@ import sun.awt.SunToolkit; import sun.misc.ManagedLocalsThread; import sun.misc.MessageUtils; import sun.misc.PerformanceLogger; -import sun.misc.Queue; import sun.security.util.SecurityConstants; /** @@ -247,8 +247,7 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { /** * AppletEvent Queue */ - private Queue queue = null; - + private LinkedBlockingQueue queue = null; public synchronized void addAppletListener(AppletListener l) { listeners = AppletEventMulticaster.add(listeners, l); @@ -276,10 +275,9 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { synchronized(this) { if (queue == null) { //System.out.println("SEND0= " + id); - queue = new Queue<>(); + queue = new LinkedBlockingQueue<>(); } - Integer eventId = Integer.valueOf(id); - queue.enqueue(eventId); + boolean inserted = queue.add(id); notifyAll(); } if (id == APPLET_QUIT) { @@ -303,8 +301,8 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { while (queue == null || queue.isEmpty()) { wait(); } - Integer eventId = queue.dequeue(); - return new AppletEvent(this, eventId.intValue(), null); + int eventId = queue.take(); + return new AppletEvent(this, eventId, null); } boolean emptyEventQueue() { From 5b80991feaf1f0c2ea8ec799076d88610566fa8e Mon Sep 17 00:00:00 2001 From: Sergei Kovalev Date: Fri, 11 Dec 2015 16:35:59 +0300 Subject: [PATCH 037/151] 8078423: [TESTBUG] javax/print/PrintSEUmlauts/PrintSEUmlauts.java relies on system locale Reviewed-by: martin --- jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java index f87549747b2..962ef5e8bc0 100644 --- a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java +++ b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java @@ -107,14 +107,14 @@ public class PrintSEUmlauts implements Printable { System.err.println("printing content"); System.err.println(content); } - throw new RuntimeException("Expected to represent 'ä' but not found!"); + throw new RuntimeException("Expected to represent '\u00e4' but not found!"); } System.err.println("SUCCESS"); } public int print(Graphics g, PageFormat pf, int pg) { if (pg > 0) return NO_SUCH_PAGE; - g.drawString("ä", 100, 100); + g.drawString("\u00e4", 100, 100); return PAGE_EXISTS; } } From ec26043caf3ca01d93a6dfaa1ac1a30e50149768 Mon Sep 17 00:00:00 2001 From: Shinya Yoshida Date: Fri, 11 Dec 2015 11:20:10 -0800 Subject: [PATCH 038/151] 8144903: JShell: determine incorrectly the type of the expression which is array type of captured type Fix and clean-up the processing of types (esp. captured types) into type names for use in generated temp vars Reviewed-by: mcimadamore, jlahoda, rfield --- .../share/classes/jdk/jshell/TypePrinter.java | 35 ++++++++++++++----- langtools/test/jdk/jshell/TypeNameTest.java | 27 ++++++++------ langtools/test/jdk/jshell/VariablesTest.java | 11 ++++++ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java index 2ac9530f0a6..e35fe5e7d7b 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java @@ -41,15 +41,15 @@ import java.util.function.BinaryOperator; * Print types in source form. */ class TypePrinter extends Printer { + private static final String OBJECT = "Object"; private final JavacMessages messages; private final BinaryOperator fullClassNameAndPackageToClass; - private final Type typeToPrint; + private boolean useWildCard = false; TypePrinter(JavacMessages messages, BinaryOperator fullClassNameAndPackageToClass, Type typeToPrint) { this.messages = messages; this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass; - this.typeToPrint = typeToPrint; } @Override @@ -64,21 +64,40 @@ class TypePrinter extends Printer { @Override public String visitCapturedType(Type.CapturedType t, Locale locale) { - if (t == typeToPrint) { - return visit(t.getUpperBound(), locale); - } else { - return visit(t.wildcard, locale); + return visit(t.wildcard, locale); + } + + @Override + public String visitWildcardType(Type.WildcardType wt, Locale locale) { + if (useWildCard) { // at TypeArgument(ex: List) + return super.visitWildcardType(wt, locale); + } else { // at TopLevelType(ex: ? extends List, ? extends Number[][]) + Type extendsBound = wt.getExtendsBound(); + return extendsBound == null + ? OBJECT + : visit(extendsBound, locale); } } @Override public String visitType(Type t, Locale locale) { String s = (t.tsym == null || t.tsym.name == null) - ? "Object" // none + ? OBJECT // none : t.tsym.name.toString(); return s; } + @Override + public String visitClassType(ClassType ct, Locale locale) { + boolean prevUseWildCard = useWildCard; + try { + useWildCard = true; + return super.visitClassType(ct, locale); + } finally { + useWildCard = prevUseWildCard; + } + } + /** * Converts a class name into a (possibly localized) string. Anonymous * inner classes get converted into a localized string. @@ -101,7 +120,7 @@ class TypePrinter extends Printer { } return s.toString(); ***/ - return "Object"; + return OBJECT; } else if (sym.name.length() == 0) { // Anonymous String s; diff --git a/langtools/test/jdk/jshell/TypeNameTest.java b/langtools/test/jdk/jshell/TypeNameTest.java index 41dbe7004cb..4f1b9cef418 100644 --- a/langtools/test/jdk/jshell/TypeNameTest.java +++ b/langtools/test/jdk/jshell/TypeNameTest.java @@ -23,7 +23,8 @@ /* * @test - * @summary null test + * @bug 8144903 + * @summary Tests for determining the type from the expression * @build KullaTesting TestingInputStream * @run testng TypeNameTest */ @@ -34,7 +35,6 @@ import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.VALID; import static org.testng.Assert.assertEquals; -import static jdk.jshell.Snippet.Status.OVERWRITTEN; @Test public class TypeNameTest extends KullaTesting { @@ -62,6 +62,11 @@ public class TypeNameTest extends KullaTesting { assertEquals(sn.typeName(), "Class"); } + public void testArrayTypeOfCapturedTypeName() { + VarSnippet sn = (VarSnippet) varKey(assertEval("\"\".getClass().getEnumConstants();")); + assertEquals(sn.typeName(), "String[]"); + } + public void testJavaLang() { VarSnippet sn = (VarSnippet) varKey(assertEval("\"\";")); assertEquals(sn.typeName(), "String"); @@ -83,14 +88,16 @@ public class TypeNameTest extends KullaTesting { VarSnippet sn3 = (VarSnippet) varKey(assertEval("list3.iterator().next()")); assertEquals(sn3.typeName(), "Object"); assertEval("class Test1 { public X get() { return null; } }"); - Snippet x = varKey(assertEval("Test1 x = new Test1<>();")); - VarSnippet sn4 = (VarSnippet) varKey(assertEval("x.get()")); - assertEquals(sn4.typeName(), "CharSequence"); - assertEval("class Foo { public X get() { return null; } }"); - assertEval("Foo x = new Foo<>();", - ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - VarSnippet sn5 = (VarSnippet) varKey(assertEval("x.get()")); + Snippet x = varKey(assertEval("Test1 test1 = new Test1<>();")); + VarSnippet sn4 = (VarSnippet) varKey(assertEval("test1.get()")); + assertEquals(sn4.typeName(), "Object"); + assertEval("class Test2 { public X get() { return null; } }"); + assertEval("Test2 test2 = new Test2<>();"); + VarSnippet sn5 = (VarSnippet) varKey(assertEval("test2.get()")); assertEquals(sn5.typeName(), "Object"); + assertEval("class Test3 { T[][] get() { return null; } }", added(VALID)); + assertEval("Test3 test3 = new Test3<>();"); + VarSnippet sn6 = (VarSnippet) varKey(assertEval("test3.get()")); + assertEquals(sn6.typeName(), "String[][]"); } } diff --git a/langtools/test/jdk/jshell/VariablesTest.java b/langtools/test/jdk/jshell/VariablesTest.java index 73a25a372c1..3a374a0b52c 100644 --- a/langtools/test/jdk/jshell/VariablesTest.java +++ b/langtools/test/jdk/jshell/VariablesTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8144903 * @summary Tests for EvaluationState.variables * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng VariablesTest @@ -184,6 +185,16 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + public void variablesTemporaryArrayOfCapturedType() { + assertEval("class Test { T[][] get() { return null; } }", added(VALID)); + assertEval("Test test() { return new Test<>(); }", added(VALID)); + assertEval("test().get()", added(VALID)); + assertVariables(variable("String[][]", "$1")); + assertEval("\"\".getClass().getEnumConstants()", added(VALID)); + assertVariables(variable("String[][]", "$1"), variable("String[]", "$2")); + assertActiveKeys(); + } + public void variablesClassReplace() { assertEval("import java.util.*;", added(VALID)); Snippet var = varKey(assertEval("List list = new ArrayList<>();", "[]", From 5b1765f25dc24d89046d2acf08859b68301d145e Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 11 Dec 2015 11:38:18 -0800 Subject: [PATCH 039/151] 8144245: [PIT] javax/imageio/plugins/shared/WriteAfterAbort.java Reset stream position after abort; change IAEs to NPEs. Reviewed-by: prr, serb --- .../com/sun/imageio/plugins/tiff/TIFFIFD.java | 9 +- .../imageio/plugins/tiff/TIFFImageWriter.java | 56 ++- jdk/test/ProblemList.txt | 2 - .../plugins/shared/WriteAfterAbort.java | 16 +- .../tiff/WriteToSequenceAfterAbort.java | 376 ++++++++++++++++++ 5 files changed, 449 insertions(+), 10 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java index 6803f634762..7c14f8daf85 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java @@ -472,6 +472,13 @@ public class TIFFIFD extends TIFFDirectory { // Read tag number, value type, and value count. int tagNumber = stream.readUnsignedShort(); int type = stream.readUnsignedShort(); + int sizeOfType; + try { + sizeOfType = TIFFTag.getSizeOfType(type); + } catch (IllegalArgumentException e) { + throw new IIOException("Illegal type " + type + + " for tag number " + tagNumber, e); + } int count = (int)stream.readUnsignedInt(); // Get the associated TIFFTag. @@ -510,7 +517,7 @@ public class TIFFIFD extends TIFFDirectory { } } - int size = count*TIFFTag.getSizeOfType(type); + int size = count*sizeOfType; if (size > 4 || tag.isIFDPointer()) { // The IFD entry value is a pointer to the actual field value. long offset = stream.readUnsignedInt(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java index 08c1f0ecb9a..6a90e0677c9 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java @@ -205,6 +205,10 @@ public class TIFFImageWriter extends ImageWriter { // Next available space. private long nextSpace = 0L; + private long prevStreamPosition; + private long prevHeaderPosition; + private long prevNextSpace; + // Whether a sequence is being written. private boolean isWritingSequence = false; private boolean isInsertingEmpty = false; @@ -2300,7 +2304,14 @@ public class TIFFImageWriter extends ImageWriter { public void write(IIOMetadata sm, IIOImage iioimage, ImageWriteParam p) throws IOException { + if (stream == null) { + throw new IllegalStateException("output == null!"); + } + markPositions(); write(sm, iioimage, p, true, true); + if (abortRequested()) { + resetPositions(); + } } private void writeHeader() throws IOException { @@ -2333,7 +2344,7 @@ public class TIFFImageWriter extends ImageWriter { throw new IllegalStateException("output == null!"); } if (iioimage == null) { - throw new NullPointerException("image == null!"); + throw new IllegalArgumentException("image == null!"); } if(iioimage.hasRaster() && !canWriteRasters()) { throw new UnsupportedOperationException @@ -2767,7 +2778,7 @@ public class TIFFImageWriter extends ImageWriter { throw new IllegalStateException("Output not set!"); } if (image == null) { - throw new NullPointerException("image == null!"); + throw new IllegalArgumentException("image == null!"); } // Locate the position of the old IFD (ifd) and the location @@ -2779,9 +2790,16 @@ public class TIFFImageWriter extends ImageWriter { // imageIndex is < -1 or is too big thereby satisfying the spec. locateIFD(imageIndex, ifdpos, ifd); + markPositions(); + // Seek to the position containing the pointer to the old IFD. stream.seek(ifdpos[0]); + // Save the previous pointer value in case of abort. + stream.mark(); + long prevPointerValue = stream.readUnsignedInt(); + stream.reset(); + // Update next space pointer in anticipation of next write. if(ifdpos[0] + 4 > nextSpace) { nextSpace = ifdpos[0] + 4; @@ -2805,6 +2823,12 @@ public class TIFFImageWriter extends ImageWriter { // Update the new IFD to point to the old IFD. stream.writeInt((int)ifd[0]); // Don't need to update nextSpace here as already done in write(). + + if (abortRequested()) { + stream.seek(ifdpos[0]); + stream.writeInt((int)prevPointerValue); + resetPositions(); + } } // ----- BEGIN insert/writeEmpty methods ----- @@ -2834,7 +2858,7 @@ public class TIFFImageWriter extends ImageWriter { } if(imageType == null) { - throw new NullPointerException("imageType == null!"); + throw new IllegalArgumentException("imageType == null!"); } if(width < 1 || height < 1) { @@ -2891,6 +2915,10 @@ public class TIFFImageWriter extends ImageWriter { IIOMetadata imageMetadata, List thumbnails, ImageWriteParam param) throws IOException { + if (stream == null) { + throw new IllegalStateException("output == null!"); + } + checkParamsEmpty(imageType, width, height, thumbnails); this.isWritingEmpty = true; @@ -2901,8 +2929,12 @@ public class TIFFImageWriter extends ImageWriter { 0, 0, emptySM.getWidth(), emptySM.getHeight(), emptySM, imageType.getColorModel()); + markPositions(); write(streamMetadata, new IIOImage(emptyImage, null, imageMetadata), param, true, false); + if (abortRequested()) { + resetPositions(); + } } public void endInsertEmpty() throws IOException { @@ -3015,7 +3047,7 @@ public class TIFFImageWriter extends ImageWriter { throw new IllegalStateException("Output not set!"); } if (region == null) { - throw new NullPointerException("region == null!"); + throw new IllegalArgumentException("region == null!"); } if (region.getWidth() < 1) { throw new IllegalArgumentException("region.getWidth() < 1!"); @@ -3200,7 +3232,7 @@ public class TIFFImageWriter extends ImageWriter { } if (image == null) { - throw new NullPointerException("image == null!"); + throw new IllegalArgumentException("image == null!"); } if (!inReplacePixelsNest) { @@ -3559,6 +3591,20 @@ public class TIFFImageWriter extends ImageWriter { // ----- END replacePixels methods ----- + // Save stream positions for use when aborted. + private void markPositions() throws IOException { + prevStreamPosition = stream.getStreamPosition(); + prevHeaderPosition = headerPosition; + prevNextSpace = nextSpace; + } + + // Reset to positions saved by markPositions(). + private void resetPositions() throws IOException { + stream.seek(prevStreamPosition); + headerPosition = prevHeaderPosition; + nextSpace = prevNextSpace; + } + public void reset() { super.reset(); diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 51abaacbf53..2a18c6adef2 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -310,8 +310,6 @@ javax/sound/midi/Gervill/SoftProvider/GetDevice.java generic-all # jdk_imageio -javax/imageio/plugins/shared/WriteAfterAbort.java generic-all - ############################################################################ # jdk_swing diff --git a/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java b/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java index 4b503d2fe6f..f1be068cdfe 100644 --- a/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java +++ b/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java @@ -130,13 +130,25 @@ public final class WriteAfterAbort implements IIOWriteProgressListener { ImageWriterSpi.class, provider -> true, true); // Validates all supported ImageWriters + int numFailures = 0; while (iter.hasNext()) { final WriteAfterAbort writeAfterAbort = new WriteAfterAbort(); final ImageWriter writer = iter.next().createWriterInstance(); System.out.println("ImageWriter = " + writer); - writeAfterAbort.test(writer); + try { + writeAfterAbort.test(writer); + } catch (Exception e) { + System.err.println("Test failed for \"" + + writer.getOriginatingProvider().getFormatNames()[0] + + "\" format."); + numFailures++; + } + } + if (numFailures == 0) { + System.out.println("Test passed."); + } else { + throw new RuntimeException("Test failed."); } - System.out.println("Test passed"); } // Callbacks diff --git a/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java b/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java new file mode 100644 index 00000000000..55461f36f24 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java @@ -0,0 +1,376 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriter; +import javax.imageio.event.IIOWriteProgressListener; +import javax.imageio.stream.ImageOutputStream; + +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Vector; +import javax.imageio.IIOImage; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +/** + * @test + * @bug 8144245 + * @summary Ensure aborting write works properly for a TIFF sequence. + */ +public final class WriteToSequenceAfterAbort implements IIOWriteProgressListener { + + private volatile boolean abortFlag = true; + private volatile boolean isAbortCalled; + private volatile boolean isCompleteCalled; + private volatile boolean isProgressCalled; + private volatile boolean isStartedCalled; + private static final int WIDTH = 100; + private static final int HEIGHT = 100; + private static final int NUM_TILES_XY = 3; + + private class TiledImage implements RenderedImage { + private final BufferedImage tile; + private final BufferedImage image; + private final int numXTiles, numYTiles; + private boolean isImageInitialized = false; + + TiledImage(BufferedImage tile, int numXTiles, int numYTiles) { + this.tile = tile; + this.numXTiles = numXTiles; + this.numYTiles = numYTiles; + image = new BufferedImage(getWidth(), getHeight(), tile.getType()); + } + + @Override + public Vector getSources() { + return null; + } + + @Override + public Object getProperty(String string) { + return java.awt.Image.UndefinedProperty; + } + + @Override + public String[] getPropertyNames() { + return new String[0]; + } + + @Override + public ColorModel getColorModel() { + return tile.getColorModel(); + } + + @Override + public SampleModel getSampleModel() { + return tile.getSampleModel(); + } + + @Override + public int getWidth() { + return numXTiles*tile.getWidth(); + } + + @Override + public int getHeight() { + return numYTiles*tile.getHeight(); + } + + @Override + public int getMinX() { + return 0; + } + + @Override + public int getMinY() { + return 0; + } + + @Override + public int getNumXTiles() { + return numXTiles; + } + + @Override + public int getNumYTiles() { + return numYTiles; + } + + @Override + public int getMinTileX() { + return 0; + } + + @Override + public int getMinTileY() { + return 0; + } + + @Override + public int getTileWidth() { + return tile.getWidth(); + } + + @Override + public int getTileHeight() { + return tile.getHeight(); + } + + @Override + public int getTileGridXOffset() { + return 0; + } + + @Override + public int getTileGridYOffset() { + return 0; + } + + @Override + public Raster getTile(int x, int y) { + WritableRaster r = tile.getRaster(); + return r.createWritableTranslatedChild(x*tile.getWidth(), + y*tile.getHeight()); + } + + @Override + public Raster getData() { + return getAsBufferedImage().getData(); + } + + @Override + public Raster getData(Rectangle r) { + return getAsBufferedImage().getData(r); + } + + @Override + public WritableRaster copyData(WritableRaster wr) { + return getAsBufferedImage().copyData(wr); + } + + public BufferedImage getAsBufferedImage() { + synchronized (image) { + if (!isImageInitialized) { + int tx0 = getMinTileX(), ty0 = getMinTileY(); + int txN = tx0 + getNumXTiles(), tyN = ty0 + getNumYTiles(); + for (int j = ty0; j < tyN; j++) { + for (int i = tx0; i < txN; i++) { + image.setData(getTile(i, j)); + } + } + } + isImageInitialized = true; + } + return image; + } + } + + private void test(final ImageWriter writer) throws IOException { + String suffix = writer.getOriginatingProvider().getFileSuffixes()[0]; + + // Image initialization + BufferedImage imageUpperLeft = + new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY); + Graphics2D g = imageUpperLeft.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH/2, HEIGHT/2); + g.dispose(); + BufferedImage imageLowerRight = + new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY); + g = imageLowerRight.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2); + g.dispose(); + TiledImage[] images = new TiledImage[] { + new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY), + new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY), + new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY), + new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY) + }; + + // File initialization + File file = File.createTempFile("temp", "." + suffix); + file.deleteOnExit(); + FileOutputStream fos = new SkipWriteOnAbortOutputStream(file); + ImageOutputStream ios = ImageIO.createImageOutputStream(fos); + writer.setOutput(ios); + writer.addIIOWriteProgressListener(this); + + writer.prepareWriteSequence(null); + boolean[] abortions = new boolean[] {true, false, true, false}; + for (int i = 0; i < 4; i++) { + abortFlag = abortions[i]; + isAbortCalled = false; + isCompleteCalled = false; + isProgressCalled = false; + isStartedCalled = false; + + TiledImage image = images[i]; + if (abortFlag) { + // This write will be aborted, and file will not be touched + writer.writeToSequence(new IIOImage(image, null, null), null); + if (!isStartedCalled) { + throw new RuntimeException("Started should be called"); + } + if (!isProgressCalled) { + throw new RuntimeException("Progress should be called"); + } + if (!isAbortCalled) { + throw new RuntimeException("Abort should be called"); + } + if (isCompleteCalled) { + throw new RuntimeException("Complete should not be called"); + } + } else { + // This write should be completed successfully and the file should + // contain correct image data. + writer.writeToSequence(new IIOImage(image, null, null), null); + if (!isStartedCalled) { + throw new RuntimeException("Started should be called"); + } + if (!isProgressCalled) { + throw new RuntimeException("Progress should be called"); + } + if (isAbortCalled) { + throw new RuntimeException("Abort should not be called"); + } + if (!isCompleteCalled) { + throw new RuntimeException("Complete should be called"); + } + } + } + + writer.endWriteSequence(); + writer.dispose(); + ios.close(); + + // Validates content of the file. + ImageReader reader = ImageIO.getImageReader(writer); + ImageInputStream iis = ImageIO.createImageInputStream(file); + reader.setInput(iis); + for (int i = 0; i < 2; i++) { + System.out.println("Testing image " + i); + BufferedImage imageRead = reader.read(i); + BufferedImage imageWrite = images[2 * i].getAsBufferedImage(); + for (int x = 0; x < WIDTH; ++x) { + for (int y = 0; y < HEIGHT; ++y) { + if (imageRead.getRGB(x, y) != imageWrite.getRGB(x, y)) { + throw new RuntimeException("Test failed for image " + i); + } + } + } + } + } + + public static void main(final String[] args) throws IOException { + WriteToSequenceAfterAbort writeAfterAbort = new WriteToSequenceAfterAbort(); + ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); + writeAfterAbort.test(writer); + System.out.println("Test passed."); + } + + // Callbacks + + @Override + public void imageComplete(ImageWriter source) { + isCompleteCalled = true; + } + + @Override + public void imageProgress(ImageWriter source, float percentageDone) { + isProgressCalled = true; + if (percentageDone > 50 && abortFlag) { + source.abort(); + } + } + + @Override + public void imageStarted(ImageWriter source, int imageIndex) { + isStartedCalled = true; + } + + @Override + public void writeAborted(final ImageWriter source) { + isAbortCalled = true; + } + + @Override + public void thumbnailComplete(ImageWriter source) { + } + + @Override + public void thumbnailProgress(ImageWriter source, float percentageDone) { + } + + @Override + public void thumbnailStarted(ImageWriter source, int imageIndex, + int thumbnailIndex) { + } + + /** + * We need to skip writes on abort, because content of the file after abort + * is undefined. + */ + private class SkipWriteOnAbortOutputStream extends FileOutputStream { + + SkipWriteOnAbortOutputStream(File file) throws FileNotFoundException { + super(file); + } + + @Override + public void write(int b) throws IOException { + if (!abortFlag) { + super.write(b); + } + } + + @Override + public void write(byte[] b) throws IOException { + if (!abortFlag) { + super.write(b); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (!abortFlag) { + super.write(b, off, len); + } + } + } +} + From ea676129ea9b9de8b78ac253cefea5645ebb015d Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Fri, 11 Dec 2015 12:01:26 -0800 Subject: [PATCH 040/151] 8068839: newDuration(x) produces incorrect outputs for some values of x Reviewed-by: rriggs, lancea --- .../internal/jaxp/datatype/DurationImpl.java | 6 ++- .../unittest/datatype/JDK8068839Test.java | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java index b8724a70a34..0b96a733cff 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java @@ -357,7 +357,7 @@ class DurationImpl * The length of the duration in milliseconds. */ protected DurationImpl(final long durationInMilliSeconds) { - + boolean is0x8000000000000000L = false; long l = durationInMilliSeconds; if (l > 0) { @@ -368,6 +368,7 @@ class DurationImpl if (l == 0x8000000000000000L) { // negating 0x8000000000000000L causes an overflow l++; + is0x8000000000000000L = true; } l *= -1; } @@ -406,7 +407,8 @@ class DurationImpl // seconds & milliseconds int2long = (gregorianCalendar.get(Calendar.SECOND) * 1000) - + gregorianCalendar.get(Calendar.MILLISECOND); + + gregorianCalendar.get(Calendar.MILLISECOND) + + (is0x8000000000000000L ? 1 : 0); this.seconds = BigDecimal.valueOf(int2long, 3); } diff --git a/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java b/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java new file mode 100644 index 00000000000..636cf680876 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package datatype; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; + +import org.testng.Assert; +import org.testng.annotations.Test; + +/* + * @bug 8068839 + * @summary Verifies that Duration's edge cases + */ +public class JDK8068839Test { + + @Test + public void test() throws DatatypeConfigurationException { + DatatypeFactory df = DatatypeFactory.newInstance(); + Duration durationx = df.newDuration(Long.MIN_VALUE); + Assert.assertEquals(durationx.toString(), "-P292277024Y7M16DT7H12M55.808S"); + durationx = df.newDuration(Long.MAX_VALUE); + Assert.assertEquals(durationx.toString(), "P292277024Y7M16DT7H12M55.807S"); + } + +} From a3e2ce543cd9e7c283ef7a44905bbf829e913969 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 11 Dec 2015 15:07:35 -0800 Subject: [PATCH 041/151] 8144997: "IIOException: Field data is past end-of-stream" when calling TIFFImageReader.read() Instead of failing for an IFD entry with bad type or offset, continue with the next entry. Reviewed-by: prr --- .../classes/com/sun/imageio/plugins/tiff/TIFFIFD.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java index 7c14f8daf85..e8f4a5d05b3 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java @@ -475,9 +475,10 @@ public class TIFFIFD extends TIFFDirectory { int sizeOfType; try { sizeOfType = TIFFTag.getSizeOfType(type); - } catch (IllegalArgumentException e) { - throw new IIOException("Illegal type " + type - + " for tag number " + tagNumber, e); + } catch (IllegalArgumentException ignored) { + // Continue with the next IFD entry. + stream.skipBytes(4); + continue; } int count = (int)stream.readUnsignedInt(); @@ -524,7 +525,7 @@ public class TIFFIFD extends TIFFDirectory { // Check whether the the field value is within the stream. if (haveStreamLength && offset + size > streamLength) { - throw new IIOException("Field data is past end-of-stream"); + continue; } // Add a TIFFIFDEntry as a placeholder. This avoids a mark, From 82c454ff4a33428722d3ebfbfd90b3269df65f23 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Fri, 11 Dec 2015 17:01:01 -0800 Subject: [PATCH 042/151] 8144952: add wildcards to the Map.ofEntries() method Reviewed-by: darcy, psandoz, chegar --- jdk/src/java.base/share/classes/java/util/Map.java | 4 ++-- jdk/test/java/util/Map/MapFactories.java | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/Map.java b/jdk/src/java.base/share/classes/java/util/Map.java index f958607dfc5..0967523eba3 100644 --- a/jdk/src/java.base/share/classes/java/util/Map.java +++ b/jdk/src/java.base/share/classes/java/util/Map.java @@ -1670,9 +1670,9 @@ public interface Map { */ @SafeVarargs @SuppressWarnings("varargs") - static Map ofEntries(Entry... entries) { + static Map ofEntries(Entry... entries) { Map map = new HashMap<>(entries.length * 4 / 3 + 1); // throws NPE if entries is null - for (Entry e : entries) { + for (Entry e : entries) { // next line throws NPE if e is null map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue())); } diff --git a/jdk/test/java/util/Map/MapFactories.java b/jdk/test/java/util/Map/MapFactories.java index 1bdb020680d..b8ff0c9f3f2 100644 --- a/jdk/test/java/util/Map/MapFactories.java +++ b/jdk/test/java/util/Map/MapFactories.java @@ -377,4 +377,13 @@ public class MapFactories { assertEquals(sie.toString(), kvh1.toString()); } + // compile-time test of wildcards + @Test + public void entryWildcardTests() { + Map.Entry e1 = Map.entry(1, 2.0); + Map.Entry e2 = Map.entry(3.0f, 4L); + Map map = Map.ofEntries(e1, e2); + assertEquals(map.size(), 2); + } + } From 3d4ea51ab10f16706fcea9c0ccb8151dbe59387e Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 11 Dec 2015 19:06:40 -0800 Subject: [PATCH 043/151] 8140470: javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java failed with AccessControlException Reviewed-by: mullan --- .../crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java b/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java index 014a7a6ab38..ca3be869c4d 100644 --- a/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java +++ b/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -33,8 +33,6 @@ import java.io.*; import java.net.*; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.Policy; -import java.security.URIParameter; import java.util.ArrayList; import java.util.Collections; import javax.xml.crypto.dsig.*; @@ -115,10 +113,8 @@ public class XMLDSigWithSecMgr implements Runnable { // the policy only grants this test SocketPermission to accept, resolve // and connect to localhost so that it can dereference 2nd reference - URI policyURI = - new File(System.getProperty("test.src", "."), "policy").toURI(); - Policy.setPolicy - (Policy.getInstance("JavaPolicy", new URIParameter(policyURI))); + System.setProperty("java.security.policy", + System.getProperty("test.src", ".") + File.separator + "policy"); System.setSecurityManager(new SecurityManager()); try { From 2a1775f3b1720236cb262f077bfec92d84465db8 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sun, 13 Dec 2015 15:10:13 +0100 Subject: [PATCH 044/151] 8145007: Pattern splitAsStream is not late binding as required by the specification Reviewed-by: chegar, psandoz --- .../classes/java/util/regex/Pattern.java | 19 +++++++++---------- .../java/util/regex/PatternStreamTest.java | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java index e4f64db438a..3a6ac6f56a8 100644 --- a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -5814,7 +5814,7 @@ NEXT: while (i <= last) { */ public Stream splitAsStream(final CharSequence input) { class MatcherIterator implements Iterator { - private final Matcher matcher; + private Matcher matcher; // The start position of the next sub-sequence of input // when current == input.length there are no more elements private int current; @@ -5823,14 +5823,6 @@ NEXT: while (i <= last) { // > 0 if there are N next empty elements private int emptyElementCount; - MatcherIterator() { - this.matcher = matcher(input); - // If the input is an empty string then the result can only be a - // stream of the input. Induce that by setting the empty - // element count to 1 - this.emptyElementCount = input.length() == 0 ? 1 : 0; - } - public String next() { if (!hasNext()) throw new NoSuchElementException(); @@ -5846,6 +5838,13 @@ NEXT: while (i <= last) { } public boolean hasNext() { + if (matcher == null) { + matcher = matcher(input); + // If the input is an empty string then the result can only be a + // stream of the input. Induce that by setting the empty + // element count to 1 + emptyElementCount = input.length() == 0 ? 1 : 0; + } if (nextElement != null || emptyElementCount > 0) return true; diff --git a/jdk/test/java/util/regex/PatternStreamTest.java b/jdk/test/java/util/regex/PatternStreamTest.java index 349faad034a..1ac3bfd23e8 100644 --- a/jdk/test/java/util/regex/PatternStreamTest.java +++ b/jdk/test/java/util/regex/PatternStreamTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8016846 8024341 8071479 + * @bug 8016846 8024341 8071479 8145006 * @summary Unit tests stream and lambda-based methods on Pattern and Matcher * @library ../stream/bootlib/java.base * @build java.util.stream.OpTestCase @@ -42,6 +42,7 @@ import java.util.function.Supplier; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.LambdaTestHelpers; import java.util.stream.OpTestCase; import java.util.stream.Stream; @@ -185,6 +186,20 @@ public class PatternStreamTest extends OpTestCase { .exercise(); } + @Test + public void testLateBinding() { + Pattern pattern = Pattern.compile(","); + + StringBuilder sb = new StringBuilder("a,b,c,d,e"); + Stream stream = pattern.splitAsStream(sb); + sb.setLength(3); + assertEquals(Arrays.asList("a", "b"), stream.collect(Collectors.toList())); + + stream = pattern.splitAsStream(sb); + sb.append(",f,g"); + assertEquals(Arrays.asList("a", "b", "f", "g"), stream.collect(Collectors.toList())); + } + public void testFailfastMatchResults() { Pattern p = Pattern.compile("X"); Matcher m = p.matcher("XX"); From 38302301fd9b93956904ff3590e3700c26aab570 Mon Sep 17 00:00:00 2001 From: Shinya Yoshida Date: Sun, 13 Dec 2015 15:20:35 +0100 Subject: [PATCH 045/151] 8144675: Add a filtering collector Reviewed-by: psandoz, smarks --- .../classes/java/util/stream/Collectors.java | 49 +++++++++++++++++- .../java/util/stream/CollectorsTest.java | 50 ++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java index c3be0d97eb8..97e05c326ec 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java @@ -434,7 +434,7 @@ public final class Collectors { * stream returned by mapper * @return a collector which applies the mapping function to the input * elements and provides the flat mapped results to the downstream collector - * @since 1.9 + * @since 9 */ public static Collector flatMapping(Function> mapper, @@ -451,6 +451,53 @@ public final class Collectors { downstream.characteristics()); } + /** + * Adapts a {@code Collector} to one accepting elements of the same type + * {@code T} by applying the predicate to each input element and only + * accumulating if the predicate returns {@code true}. + * + * @apiNote + * The {@code filtering()} collectors are most useful when used in a + * multi-level reduction, such as downstream of a {@code groupingBy} or + * {@code partitioningBy}. For example, given a stream of + * {@code Employee}, to accumulate the employees in each department that have a + * salary above a certain threshold: + *
{@code
+     *     Map> wellPaidEmployeesByDepartment
+     *         = employees.stream().collect(groupingBy(Employee::getDepartment,
+     *                                              filtering(e -> e.getSalary() > 2000, toSet())));
+     * }
+ * A filtering collector differs from a stream's {@code filter()} operation. + * In this example, suppose there are no employees whose salary is above the + * threshold in some department. Using a filtering collector as shown above + * would result in a mapping from that department to an empty {@code Set}. + * If a stream {@code filter()} operation were done instead, there would be + * no mapping for that department at all. + * + * @param the type of the input elements + * @param intermediate accumulation type of the downstream collector + * @param result type of collector + * @param predicate a predicate to be applied to the input elements + * @param downstream a collector which will accept values that match the + * predicate + * @return a collector which applies the predicate to the input elements + * and provides matching elements to the downstream collector + * @since 9 + */ + public static + Collector filtering(Predicate predicate, + Collector downstream) { + BiConsumer downstreamAccumulator = downstream.accumulator(); + return new CollectorImpl<>(downstream.supplier(), + (r, t) -> { + if (predicate.test(t)) { + downstreamAccumulator.accept(r, t); + } + }, + downstream.combiner(), downstream.finisher(), + downstream.characteristics()); + } + /** * Adapts a {@code Collector} to perform an additional finishing * transformation. For example, one could adapt the {@link #toList()} diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java index 07fa5bcb5cf..d07b6eba4a7 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java @@ -56,6 +56,7 @@ import org.testng.annotations.Test; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.flatMapping; +import static java.util.stream.Collectors.filtering; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.groupingByConcurrent; import static java.util.stream.Collectors.mapping; @@ -72,7 +73,7 @@ import static java.util.stream.LambdaTestHelpers.mDoubler; /* * @test - * @bug 8071600 + * @bug 8071600 8144675 * @summary Test for collectors. */ public class CollectorsTest extends OpTestCase { @@ -118,6 +119,23 @@ public class CollectorsTest extends OpTestCase { } } + static class FilteringAssertion extends CollectorAssertion { + private final Predicate filter; + private final CollectorAssertion downstream; + + public FilteringAssertion(Predicate filter, CollectorAssertion downstream) { + this.filter = filter; + this.downstream = downstream; + } + + @Override + void assertValue(R value, Supplier> source, boolean ordered) throws ReflectiveOperationException { + downstream.assertValue(value, + () -> source.get().filter(filter), + ordered); + } + } + static class GroupingByAssertion> extends CollectorAssertion { private final Class clazz; private final Function classifier; @@ -550,6 +568,36 @@ public class CollectorsTest extends OpTestCase { new ToListAssertion<>()))); } + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + public void testGroupingByWithFiltering(String name, TestData.OfRef data) throws ReflectiveOperationException { + Function classifier = i -> i % 3; + Predicate filteringByMod2 = i -> i % 2 == 0; + Predicate filteringByUnder100 = i -> i % 2 < 100; + Predicate filteringByTrue = i -> true; + Predicate filteringByFalse = i -> false; + + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByMod2, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByMod2, + new ToListAssertion<>()))); + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByUnder100, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByUnder100, + new ToListAssertion<>()))); + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByTrue, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByTrue, + new ToListAssertion<>()))); + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByFalse, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByFalse, + new ToListAssertion<>()))); + } + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) public void testTwoLevelGroupingBy(String name, TestData.OfRef data) throws ReflectiveOperationException { Function classifier = i -> i % 6; From 062dc5fdee6a637105d8e28da75eaa9045d6ba4d Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 14 Dec 2015 11:51:33 +0100 Subject: [PATCH 046/151] 8145008: Add libelf package to Linux devkit Reviewed-by: ihse --- make/devkit/Tools.gmk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index e5cb19ff701..aa7482a8f20 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -82,7 +82,9 @@ RPM_LIST := \ libXi libXi-devel \ libXdmcp libXdmcp-devel \ libXau libXau-devel \ - libgcc + libgcc \ + elfutils elfutils-devel \ + elfutils-libelf elfutils-libelf-devel ifeq ($(ARCH),x86_64) From 64634dc9a4d34a43577e8e26696ec5195d52be8d Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Mon, 14 Dec 2015 14:02:59 +0100 Subject: [PATCH 047/151] 8144221: fix Nashorn shebang argument handling on Mac/Linux Reviewed-by: jlaskey, lagergren --- nashorn/make/build.xml | 10 +- .../internal/runtime/ScriptingFunctions.java | 13 +- .../classes/jdk/nashorn/tools/Shell.java | 133 +++++++-------- nashorn/test/script/nosecurity/JDK-8144221.js | 155 ++++++++++++++++++ .../script/nosecurity/JDK-8144221.js.EXPECTED | 68 ++++++++ .../test/script/nosecurity/os-not-windows.js | 37 +++++ 6 files changed, 347 insertions(+), 69 deletions(-) create mode 100644 nashorn/test/script/nosecurity/JDK-8144221.js create mode 100644 nashorn/test/script/nosecurity/JDK-8144221.js.EXPECTED create mode 100644 nashorn/test/script/nosecurity/os-not-windows.js diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 9f5d48cae50..32d08ad694b 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -48,12 +48,12 @@ - + - + diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java index eb4fb4dfa56..5f849ea38b5 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -278,9 +278,8 @@ public final class ScriptingFunctions { * @param str a {@link String} to tokenize. * @return a {@link List} of {@link String}s representing the tokens that * constitute the string. - * @throws IOException in case {@link StreamTokenizer#nextToken()} raises it. */ - public static List tokenizeString(final String str) throws IOException { + public static List tokenizeString(final String str) { final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(str)); tokenizer.resetSyntax(); tokenizer.wordChars(0, 255); @@ -290,7 +289,7 @@ public final class ScriptingFunctions { tokenizer.quoteChar('\''); final List tokenList = new ArrayList<>(); final StringBuilder toAppend = new StringBuilder(); - while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { + while (nextToken(tokenizer) != StreamTokenizer.TT_EOF) { final String s = tokenizer.sval; // The tokenizer understands about honoring quoted strings and recognizes // them as one token that possibly contains multiple space-separated words. @@ -309,4 +308,12 @@ public final class ScriptingFunctions { } return tokenList; } + + private static int nextToken(final StreamTokenizer tokenizer) { + try { + return tokenizer.nextToken(); + } catch (final IOException ioe) { + return StreamTokenizer.TT_EOF; + } + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java index 41669f814ba..e92eca362b9 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java @@ -25,23 +25,6 @@ package jdk.nashorn.tools; -import static jdk.nashorn.internal.runtime.Source.sourceFor; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.stream.Collectors; - import jdk.nashorn.api.scripting.NashornException; import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler.CompilationPhases; @@ -60,10 +43,32 @@ import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.ScriptingFunctions; import jdk.nashorn.internal.runtime.Symbol; import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; import jdk.nashorn.internal.runtime.options.Options; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +import static jdk.nashorn.internal.runtime.Source.sourceFor; + /** * Command line Shell for processing JavaScript files. */ @@ -203,8 +208,7 @@ public class Shell implements PartialParser { // parse options if (args != null) { try { - // FIXME: preprocessArgs does not yet work fine - final String[] prepArgs = args; // preprocessArgs(args); + final String[] prepArgs = preprocessArgs(args); options.process(prepArgs); } catch (final IllegalArgumentException e) { werr.println(bundle.getString("shell.usage")); @@ -236,35 +240,53 @@ public class Shell implements PartialParser { } /** - * Preprocess the command line arguments passed in by the shell. This checks, for each of the arguments, whether it - * can be a file name, and if so, whether the file exists. If the file exists and begins with a shebang line, and - * the arguments on that line are a prefix of {@code args} with the file removed, it is assumed that a script file - * being executed via shebang was found, and it is moved to the appropriate position in the argument list. The first - * such match is used. + * Preprocess the command line arguments passed in by the shell. This method checks, for the first non-option + * argument, whether the file denoted by it begins with a shebang line. If so, it is assumed that execution in + * shebang mode is intended. The consequence of this is that the identified script file will be treated as the + * only script file, and all subsequent arguments will be regarded as arguments to the script. *

- * This method canonicalizes the command line arguments to the form {@code -- }, - * where the last of the {@code scripts} is the one being run in shebang fashion. + * This method canonicalizes the command line arguments to the form {@code