提交 3394b8ed 编写于 作者: L lana

Merge

#
# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute 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.
#
# Copyright year for beginning of Java and some of the apis
# (Needed when creating the javadocs)
FIRST_COPYRIGHT_YEAR = 1993
DOMAPI_FIRST_COPYRIGHT_YEAR = 2005
MIRROR_FIRST_COPYRIGHT_YEAR = 2004
DOCLETAPI_FIRST_COPYRIGHT_YEAR = 1993
TAGLETAPI_FIRST_COPYRIGHT_YEAR = 1993
JDI_FIRST_COPYRIGHT_YEAR = 1999
JAAS_FIRST_COPYRIGHT_YEAR = 1998
JGSS_FIRST_COPYRIGHT_YEAR = 2000
SMARTCARDIO_FIRST_COPYRIGHT_YEAR = 2005
HTTPSERVER_FIRST_COPYRIGHT_YEAR = 2005
MGMT_FIRST_COPYRIGHT_YEAR = 2003
ATTACH_FIRST_COPYRIGHT_YEAR = 2005
JCONSOLE_FIRST_COPYRIGHT_YEAR = 2006
SCTPAPI_FIRST_COPYRIGHT_YEAR = 2009
TRACING_FIRST_COPYRIGHT_YEAR = 2008
TREEAPI_FIRST_COPYRIGHT_YEAR = 2005
JNLP_FIRST_COPYRIGHT_YEAR = 1998
PLUGIN2_FIRST_COPYRIGHT_YEAR = 2007
# Oracle name
COMPANY_NAME = Oracle and/or its affiliates
# Copyright address
COMPANY_ADDRESS = 500 Oracle Parkway<br>Redwood Shores, CA 94065 USA.
# The trademark symbol
TRADEMARK = &trade;
# Common copyright lines used
# The word "Copyright" might optionally be a link to the file cpyr.html.
# The first year of copyright may vary or not be available.
# The address to the company might be optional.
COMMA:= ,
EMPTY:=
SPACE:=$(EMPTY) $(EMPTY)
COPYRIGHT_SYMBOL = &\#x00a9;
# Macros to handle the optional empty args.
# (The GNU make 3.78.1 "if" conditional is broken, fixed in GNU make 3.81)
define OptionalCopyrightUrl # url
$(shell \
if [ "$1" != "" ] ; then \
printf "<a href=\"%s\">Copyright</a>" "$1"; \
else \
printf "Copyright"; \
fi)
endef
define OptionalCopyrightFirstYear # year
$(shell \
if [ "$1" != "" ] ; then \
printf "%s," "$1";\
fi)
endef
define OptionalCompanyAddress # address
$(shell \
if [ "$1" != "" ] ; then \
printf "%s" "$1";\
fi)
endef
define CopyrightLine # optionalurl optionalfirstyear optionaladdress
$(call OptionalCopyrightUrl,$1) $(COPYRIGHT_SYMBOL)\
$(call OptionalCopyrightFirstYear,$2) $(COPYRIGHT_YEAR),\
$(COMPANY_NAME).\
$(call OptionalCompanyAddress,$3)\
All rights reserved.
endef
...@@ -230,7 +230,8 @@ endif ...@@ -230,7 +230,8 @@ endif
# Compilers, SDK, and Visual Studio (MSDEV) [32bit is different from 64bit] # Compilers, SDK, and Visual Studio (MSDEV) [32bit is different from 64bit]
ifeq ($(ARCH_DATA_MODEL), 32) ifeq ($(ARCH_DATA_MODEL), 32)
# Try looking in MSVCDIR or MSVCDir area first (set by vcvars32.bat) # Try looking in MSVCDIR or MSVCDir area first
# (set by vcvars32.bat for VC .NET, not defined in the VC 2008/2010)
ifdef MSVCDIR ifdef MSVCDIR
xMSVCDIR :="$(subst \,/,$(MSVCDIR))" xMSVCDIR :="$(subst \,/,$(MSVCDIR))"
_msvc_dir :=$(call FullPath,$(xMSVCDIR)) _msvc_dir :=$(call FullPath,$(xMSVCDIR))
...@@ -238,11 +239,6 @@ ifeq ($(ARCH_DATA_MODEL), 32) ...@@ -238,11 +239,6 @@ ifeq ($(ARCH_DATA_MODEL), 32)
ifdef MSVCDir ifdef MSVCDir
xMSVCDIR :="$(subst \,/,$(MSVCDir))" xMSVCDIR :="$(subst \,/,$(MSVCDir))"
_msvc_dir :=$(call FullPath,$(xMSVCDIR)) _msvc_dir :=$(call FullPath,$(xMSVCDIR))
else
ifneq ($(_program_files),)
xMSVCDIR :="$(_program_files)/Microsoft Visual Studio .NET 2003/Vc7"
_msvc_dir :=$(call FullPath,$(xMSVCDIR))
endif
endif endif
endif endif
# If we still don't have it, look for VSnnCOMNTOOLS (newest first), # If we still don't have it, look for VSnnCOMNTOOLS (newest first),
......
此差异已折叠。
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
# #
JAVA_JAVA_java = \ JAVA_JAVA_java = \
java/lang/Object.java \ java/lang/Object.java \
java/lang/AutoCloseable.java \
java/lang/Class.java \ java/lang/Class.java \
java/lang/Thread.java \ java/lang/Thread.java \
java/lang/Character.java \ java/lang/Character.java \
......
# #
# Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 1996, 2010 Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -62,6 +62,11 @@ POLICY_BUILD = $(LIBDIR)/security/java.policy ...@@ -62,6 +62,11 @@ POLICY_BUILD = $(LIBDIR)/security/java.policy
CACERTS_SRC = $(CACERTS_FILE) CACERTS_SRC = $(CACERTS_FILE)
CACERTS_BUILD = $(LIBDIR)/security/cacerts CACERTS_BUILD = $(LIBDIR)/security/cacerts
ifndef OPENJDK
BLACKLIST_SRC = $(CLOSED_SHARE_SRC)/lib/security/blacklist
BLACKLIST_BUILD = $(LIBDIR)/security/blacklist
endif
FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class) FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class)
# #
...@@ -69,7 +74,11 @@ FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class) ...@@ -69,7 +74,11 @@ FILES_class = $(FILES_java:%.java=$(CLASSBINDIR)/%.class)
# #
include $(BUILDDIR)/common/Rules.gmk include $(BUILDDIR)/common/Rules.gmk
ifdef OPENJDK
build: properties policy cacerts build: properties policy cacerts
else
build: properties policy cacerts blacklist
endif
install: all install: all
...@@ -79,6 +88,8 @@ policy: classes $(POLICY_BUILD) ...@@ -79,6 +88,8 @@ policy: classes $(POLICY_BUILD)
cacerts: classes $(CACERTS_BUILD) cacerts: classes $(CACERTS_BUILD)
blacklist: classes $(BLACKLIST_BUILD)
$(PROPS_BUILD): $(PROPS_SRC) $(PROPS_BUILD): $(PROPS_SRC)
$(install-file) $(install-file)
...@@ -88,9 +99,12 @@ $(POLICY_BUILD): $(POLICY_SRC) ...@@ -88,9 +99,12 @@ $(POLICY_BUILD): $(POLICY_SRC)
$(CACERTS_BUILD): $(CACERTS_SRC) $(CACERTS_BUILD): $(CACERTS_SRC)
$(install-file) $(install-file)
$(BLACKLIST_BUILD): $(BLACKLIST_SRC)
$(install-file)
clean clobber:: .delete.classlist clean clobber:: .delete.classlist
$(RM) -r $(CLASSBINDIR)/java/security $(RM) -r $(CLASSBINDIR)/java/security
$(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(RM) $(PROPS_BUILD) $(POLICY_BUILD) $(CACERTS_BUILD) $(BLACKLIST_BUILD)
# Additional Rule for building sun.security.util # Additional Rule for building sun.security.util
$(CLASSBINDIR)/%.class: $(SHARE_SRC)/sun/%.java $(CLASSBINDIR)/%.class: $(SHARE_SRC)/sun/%.java
......
...@@ -46,11 +46,11 @@ nbproject: ...@@ -46,11 +46,11 @@ nbproject:
$(RM) -r $(DEMODIR)/nbproject $(RM) -r $(DEMODIR)/nbproject
$(MKDIR) -p $(DEMODIR) $(MKDIR) -p $(DEMODIR)
( $(CD) $(SHARE_SRC)/demo && $(TAR) -cf - \ ( $(CD) $(SHARE_SRC)/demo && $(TAR) -cf - \
`find nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \ `$(FIND) nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \
( $(CD) $(DEMODIR) && $(TAR) -xf - ) ( $(CD) $(DEMODIR) && $(TAR) -xf - )
ifndef OPENJDK ifndef OPENJDK
( $(CD) $(CLOSED_SHARE_SRC)/demo && $(TAR) -cf - \ ( $(CD) $(CLOSED_SHARE_SRC)/demo && $(TAR) -cf - \
`find nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \ `$(FIND) nbproject $(SCM_DIRS_prune) -o -type f -print` ) | \
( $(CD) $(DEMODIR) && $(TAR) -xf - ) ( $(CD) $(DEMODIR) && $(TAR) -xf - )
endif endif
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* combine with an argument list of files and directories, and * combine with an argument list of files and directories, and
* write a list of items to be included in a jar file. * write a list of items to be included in a jar file.
*/ */
package build.tools.jarreorder; package build.tools.jarreorder;
import java.io.BufferedReader; import java.io.BufferedReader;
...@@ -36,74 +35,68 @@ import java.io.File; ...@@ -36,74 +35,68 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Vector;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class JarReorder { public class JarReorder {
// To deal with output // To deal with output
private static PrintStream out; private PrintStream out;
private final static boolean useTopDir = false;
private static void usage() { private void usage() {
String help; String help;
help = help =
"Usage: jar JarReorder [-o <outputfile>] <order_list> <exclude_list> <file> ...\n" "Usage: jar JarReorder [-o <outputfile>] <order_list> <exclude_list> <file> ...\n"
+ " order_list is a file containing names of files to load\n" + " order_list is a file containing names of files to load\n"
+ " in order at the end of a jar file.\n" + " in order at the end of a jar file unless\n"
+ " excluded in the exclude list.\n"
+ " exclude_list is a file containing names of files/directories\n" + " exclude_list is a file containing names of files/directories\n"
+ " NOT to be included in a jar file.\n"; + " NOT to be included in a jar file.\n"
if (useTopDir) + "\n"
help += + "The order_list or exclude_list may be replaced by a \"-\" if no\n"
" top_dir is the top of the directory structure to be searched;\n"
+ " the contents of the lists and remaining arguments are\n"
+ " relative to this.\n";
help +=
"\n"
+ "The order_list or exclude_list may be replaced by a \"_\" if no\n"
+ "data is to be provided.\n" + "data is to be provided.\n"
+ "\n" + "\n"
+ " The remaining arguments are files or directories to be included\n" + " The remaining arguments are files or directories to be included\n"
+ " in a jar file, from which will be excluded thse entries which\n" + " in a jar file, from which will be excluded those entries which\n"
+ " appear in the exclude list.\n"; + " appear in the exclude list.\n";
System.err.println(help); System.err.println(help);
System.exit(1);
} }
/* /*
* Create a list of files to be included in a jar file, such that the * Create the file list to be included in a jar file, such that the
* some the files will appear in a specific order, and allowing certain * list will appear in a specific order, and allowing certain
* files and directories to be excluded. * files and directories to be excluded.
* *
* Command line arguments are * Command path arguments are
* - optional -o outputfile * - optional -o outputfile
* - name of a file containing a list of files to be included in a jar file. * - name of a file containing a set of files to be included in a jar file.
* - name of a file containing a list of files (or directories) to be * - name of a file containing a set of files (or directories) to be
* excluded from the jar file. * excluded from the jar file.
* - names of files or directories to be searched for files to include * - names of files or directories to be searched for files to include
* in the jar file. * in the jar file.
*/ */
public static void main(String[] args) { public static void main(String[] args) {
JarReorder jr = new JarReorder();
jr.run(args);
}
private void run(String args[]) {
HashMap filesExcluded = new HashMap();
Vector filesIncluded = new Vector();
int fileArgs;
String topDirName = "";
int arglen = args.length; int arglen = args.length;
int argpos = 0; int argpos = 0;
// Look for "-o outputfilename" option // Look for "-o outputfilename" option
if ( arglen > 0 ) { if (arglen > 0) {
if ( arglen >= 2 && args[0].equals("-o") ) { if (arglen >= 2 && args[0].equals("-o")) {
try { try {
out = new PrintStream(new FileOutputStream(args[1])); out = new PrintStream(new FileOutputStream(args[1]));
} catch ( FileNotFoundException e ) { } catch (FileNotFoundException e) {
System.err.println("Error: " + e.getMessage()); System.err.println("Error: " + e.getMessage());
e.printStackTrace(System.err); e.printStackTrace(System.err);
System.exit(1); System.exit(1);
...@@ -118,128 +111,111 @@ public class JarReorder { ...@@ -118,128 +111,111 @@ public class JarReorder {
out = System.out; out = System.out;
} }
fileArgs = useTopDir ? 3 : 2; // Should be 2 or more args left
if (arglen <= 2) {
if (arglen <= fileArgs) {
usage(); usage();
System.exit(1);
} }
// Read the ordered list of files to be included in rt.jar. // Read the ordered set of files to be included in rt.jar.
// Read the list of files/directories to be excluded from rt.jar. // Read the set of files/directories to be excluded from rt.jar.
String classListFile = args[argpos];
String excludeListFile = args[argpos + 1];
argpos += 2;
arglen -= 2;
Vector orderList = readListFromFile(args[argpos], true); // Create 2 lists and a set of processed files
Vector excludeList = readListFromFile(args[argpos+1], false); List<String> orderList = readListFromFile(classListFile, true);
if (useTopDir) { List<String> excludeList = readListFromFile(excludeListFile, false);
topDirName = args[argpos+2]; Set<String> processed = new HashSet<String>();
if (!topDirName.endsWith(File.separator))
topDirName = topDirName + File.separator;
}
// Copy these lists into filesExcluded so that these files will be excluded // Create set of all files and directories excluded, then expand
// from the file list. (The orderList files will be appended later.) // that list completely
Set<String> excludeSet = new HashSet<String>(excludeList);
Set<String> allFilesExcluded = expand(null, excludeSet, processed);
for (int i = 0; i < orderList.size(); ++i) { // Indicate all these have been processed, orderList too, kept to end.
String s = (String) orderList.elementAt(i); processed.addAll(orderList);
filesExcluded.put(s, s);
}
for (int i = 0; i < excludeList.size(); ++i) {
String s = (String) excludeList.elementAt(i);
filesExcluded.put(s, s);
}
// The remaining arguments are names of files/directories to be included // The remaining arguments are names of files/directories to be included
// in the jar file. // in the jar file.
Set<String> inputSet = new HashSet<String>();
String[] files = new String[arglen - fileArgs]; for (int i = 0; i < arglen; ++i) {
for (int i = fileArgs; i < arglen; ++i) { String name = args[argpos + i];
files[i-fileArgs] = args[argpos+i]; name = cleanPath(new File(name));
filesExcluded.put(args[argpos+i], args[argpos+i]); if ( name != null && name.length() > 0 && !inputSet.contains(name) ) {
inputSet.add(name);
}
} }
// Expand file/directory list to file list excluding those // Expand file/directory input so we get a complete set (except ordered)
// read from the class list. // Should be everything not excluded and not in order list.
Set<String> allFilesIncluded = expand(null, inputSet, processed);
if (useTopDir) // Create simple sorted list so we can add ordered items at end.
expand(new File(topDirName), files, filesIncluded, filesExcluded, topDirName); List<String> allFiles = new ArrayList<String>(allFilesIncluded);
else Collections.sort(allFiles);
expand(null, files, filesIncluded, filesExcluded, null);
// Now add the ordered list to the end of the expanded list. // Now add the ordered set to the end of the list.
// Add in REVERSE ORDER, so that the first element is closest to // Add in REVERSE ORDER, so that the first element is closest to
// the end (and the index). // the end (and the index).
HashSet excludeSet = new HashSet(excludeList);
for (int i = orderList.size() - 1; i >= 0; --i) { for (int i = orderList.size() - 1; i >= 0; --i) {
String s = (String) orderList.elementAt(i); String s = orderList.get(i);
if (excludeSet.contains(s)) { if (allFilesExcluded.contains(s)) {
System.err.println("Included file " + s + " is also excluded, skipping."); System.err.println("Included order file " + s
continue; + " is also excluded, skipping.");
} else if (new File(s).exists()) {
allFiles.add(s);
} else {
System.err.println("Included order file " + s
+ " missing, skipping.");
} }
if (new File(topDirName + s).exists())
filesIncluded.addElement(s);
else
System.err.println("Included file "+s+" missing, skipping.");
} }
// Print results. // Print final results.
for (String str : allFiles) {
for (int i = 0; i < filesIncluded.size(); ++i) { out.println(str);
if (useTopDir) {
out.print("-C ");
out.print(topDirName);
out.print(" ");
}
out.println((String)filesIncluded.elementAt(i));
} }
out.flush(); out.flush();
out.close(); out.close();
} }
/* /*
* Read a file containing a list of files into a Vector. * Read a file containing a list of files and directories into a List.
*/ */
private static Vector readListFromFile(String fileName, private List<String> readListFromFile(String fileName,
boolean addClassSuffix) { boolean addClassSuffix) {
BufferedReader br = null; BufferedReader br = null;
Vector v = new Vector(2000); List<String> list = new ArrayList<String>();
// If you see "-" for the name, just assume nothing was provided.
if ("-".equals(fileName)) if ("-".equals(fileName)) {
return v; return list;
}
try { try {
br = new BufferedReader(new FileReader(fileName)); br = new BufferedReader(new FileReader(fileName));
// Read the input file a path at a time. # in column 1 is a comment.
// Read the input file a line at a time. # in column 1 is a comment.
while (true) { while (true) {
String line = null; String path = br.readLine();
line = br.readLine(); if (path == null) {
if (line == null)
break; break;
}
if (line.length() == 0 || // Look for comments
line.charAt(0) == '#') path = path.trim();
if (path.length() == 0
|| path.charAt(0) == '#') {
continue; continue;
// Convert forward or back slashes to the type expected for
// the current platform.
if (File.separatorChar == '/')
line = line.replace('\\', '/');
else
line = line.replace('/', '\\');
line = line.trim();
if (addClassSuffix) {
if (!line.endsWith(".class")) {
line = line + ".class";
} }
// Add trailing .class if necessary
if (addClassSuffix && !path.endsWith(".class")) {
path = path + ".class";
}
// Normalize the path
path = cleanPath(new File(path));
// Add to list
if (path != null && path.length() > 0 && !list.contains(path)) {
list.add(path);
} }
v.addElement(line);
} }
br.close(); br.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
...@@ -249,68 +225,89 @@ public class JarReorder { ...@@ -249,68 +225,89 @@ public class JarReorder {
e.printStackTrace(); e.printStackTrace();
System.exit(2); System.exit(2);
} }
return v; return list;
} }
/* /*
* Expands list of files to process into full list of all files that * Expands inputSet (files or dirs) into full set of all files that
* can be found by recursively descending directories. * can be found by recursively descending directories.
* @param dir root directory
* @param inputSet set of files or dirs to look into
* @param processed files or dirs already processed
* @return set of files
*/ */
private static void expand(File dir, String[] files, private Set<String> expand(File dir,
Vector includedFiles, HashMap excludedFiles, Set<String> inputSet,
String topDirName) { Set<String> processed) {
if (files == null) { Set<String> includedFiles = new HashSet<String>();
return; if (inputSet.isEmpty()) {
} return includedFiles;
for (int i = 0; i < files.length; i++) { }
File f = (dir == null) ? new File(files[i]) for (String name : inputSet) {
: new File(dir, files[i]); // Depending on start location
File f = (dir == null) ? new File(name)
: new File(dir, name);
// Normalized path to use
String path = cleanPath(f);
if (path != null && path.length() > 0
&& !processed.contains(path)) {
if (f.isFile()) { if (f.isFile()) {
String filePath = f.getPath(); // Not in the excludeList, add it to both lists
includedFiles.add(path);
if (useTopDir) { processed.add(path);
if (filePath.startsWith(topDirName)) } else if (f.isDirectory()) {
filePath = filePath.substring(topDirName.length()); // Add the directory entries
String[] dirList = f.list();
Set<String> dirInputSet = new HashSet<String>();
for (String x : dirList) {
dirInputSet.add(x);
} }
// Process all entries in this directory
if (filePath.length() >= 2 && Set<String> subList = expand(f, dirInputSet, processed);
filePath.charAt(0) == '.' && includedFiles.addAll(subList);
filePath.charAt(1) == File.separatorChar) processed.add(path);
filePath = filePath.substring(2);
if (!excludedFiles.containsKey(filePath)) {
excludedFiles.put(filePath, filePath);
includedFiles.addElement(filePath);
} }
} else if (f.isDirectory()) { }
String dirPath = f.getPath(); }
dirPath = (dirPath.endsWith(File.separator)) ? dirPath : return includedFiles;
(dirPath + File.separator);
if (useTopDir) {
if (dirPath.startsWith(topDirName))
dirPath = dirPath.substring(topDirName.length());
} }
if (dirPath.length() >= 2 && private String cleanPath(File f) {
dirPath.charAt(0) == '.' && String path = f.getPath();
dirPath.charAt(1) == File.separatorChar) if (f.isFile()) {
dirPath = dirPath.substring(2); path = cleanFilePath(path);
} else if (f.isDirectory()) {
if (!excludedFiles.containsKey(dirPath)) { path = cleanDirPath(path);
} else {
// Sort the directory list so that entries in the jar file System.err.println("WARNING: Path does not exist as file or directory: " + path);
// are in a repeatable order. The order itself is not particularly path = null;
// important. [File.list() is unpredictable.] }
return path;
String[] dirList = f.list();
Arrays.sort(dirList);
expand(f, dirList, includedFiles, excludedFiles, topDirName);
} }
private String cleanFilePath(String path) {
// Remove leading and trailing whitespace
path = path.trim();
// Make all / and \ chars one
if (File.separatorChar == '/') {
path = path.replace('\\', '/');
} else { } else {
System.err.println("Error accessing: " + f.getPath()); path = path.replace('/', '\\');
} }
// Remove leading ./
if (path.startsWith("." + File.separator)) {
path = path.substring(2);
} }
return path;
} }
private String cleanDirPath(String path) {
path = cleanFilePath(path);
// Make sure it ends with a file separator
if (!path.endsWith(File.separator)) {
path = path + File.separator;
}
return path;
}
} }
/* /*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR #define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR
#define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR #define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR
#define JVM_ERROR3 "Error: SPARC V8 processor detected; Server compiler requires V9 or better.\nUse Client compiler on V8 processors.\nCould not create the Java virtual machine." #define JVM_ERROR3 "Error: SPARC V8 processor detected; Required V9 processors or better.\nUse JDK5 client compiler for V8 processors.\n" JVM_ERROR1
#define JAR_ERROR1 "Error: Failed to load Main-Class manifest attribute from\n%s\n%s" #define JAR_ERROR1 "Error: Failed to load Main-Class manifest attribute from\n%s\n%s"
#define JAR_ERROR2 "Error: Unable to access jarfile %s" #define JAR_ERROR2 "Error: Unable to access jarfile %s"
...@@ -69,7 +69,8 @@ ...@@ -69,7 +69,8 @@
#define CFG_ERROR5 "Error: Could not determine application home." #define CFG_ERROR5 "Error: Could not determine application home."
#define CFG_ERROR6 "Error: could not open `%s'" #define CFG_ERROR6 "Error: could not open `%s'"
#define CFG_ERROR7 "Error: no known VMs. (check for corrupt jvm.cfg file)" #define CFG_ERROR7 "Error: no known VMs. (check for corrupt jvm.cfg file)"
#define CFG_ERROR8 "Error: no `%s' JVM at `%s'." #define CFG_ERROR8 "Error: missing `%s' JVM at `%s'.\nPlease install or use the JRE or JDK that contains these missing components."
#define CFG_ERROR9 "Error: could not determine JVM type."
#define SPC_ERROR1 "Error: Syntax error in version specification \"%s\"" #define SPC_ERROR1 "Error: Syntax error in version specification \"%s\""
......
/* /*
* Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -192,8 +192,8 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ ...@@ -192,8 +192,8 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
int ret; int ret;
InvocationFunctions ifn; InvocationFunctions ifn;
jlong start, end; jlong start, end;
char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN]; char jvmpath[MAXPATHLEN];
char ** original_argv = argv; char jrepath[MAXPATHLEN];
_fVersion = fullversion; _fVersion = fullversion;
_dVersion = dotversion; _dVersion = dotversion;
...@@ -225,14 +225,17 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ ...@@ -225,14 +225,17 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
*/ */
SelectVersion(argc, argv, &main_class); SelectVersion(argc, argv, &main_class);
/* copy original argv */ if (JLI_IsTraceLauncher()) {
JLI_TraceLauncher("Command line Args:\n"); int i;
original_argv = (JLI_CopyArgs(argc, (const char**)argv)); printf("Command line args:\n");
for (i = 0; i < argc ; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
}
CreateExecutionEnvironment(&argc, &argv, CreateExecutionEnvironment(&argc, &argv,
jrepath, sizeof(jrepath), jrepath, sizeof(jrepath),
jvmpath, sizeof(jvmpath), jvmpath, sizeof(jvmpath));
original_argv);
ifn.CreateJavaVM = 0; ifn.CreateJavaVM = 0;
ifn.GetDefaultJavaVMInitArgs = 0; ifn.GetDefaultJavaVMInitArgs = 0;
...@@ -301,22 +304,43 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ ...@@ -301,22 +304,43 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
return ContinueInNewThread(&ifn, argc, argv, jarfile, classname, ret); return ContinueInNewThread(&ifn, argc, argv, jarfile, classname, ret);
} }
/*
* Always detach the main thread so that it appears to have ended when
* the application's main method exits. This will invoke the
* uncaught exception handler machinery if main threw an
* exception. An uncaught exception handler cannot change the
* launcher's return code except by calling System.exit.
*
* Wait for all non-daemon threads to end, then destroy the VM.
* This will actually create a trivial new Java waiter thread
* named "DestroyJavaVM", but this will be seen as a different
* thread from the one that executed main, even though they are
* the same C thread. This allows mainThread.join() and
* mainThread.isAlive() to work as expected.
*/
#define LEAVE() \
if ((*vm)->DetachCurrentThread(vm) != 0) { \
JLI_ReportErrorMessage(JVM_ERROR2); \
ret = 1; \
} \
(*vm)->DestroyJavaVM(vm); \
return ret \
#define CHECK_EXCEPTION_NULL_LEAVE(e) \ #define CHECK_EXCEPTION_NULL_LEAVE(e) \
if ((*env)->ExceptionOccurred(env)) { \ if ((*env)->ExceptionOccurred(env)) { \
JLI_ReportExceptionDescription(env); \ JLI_ReportExceptionDescription(env); \
goto leave; \ LEAVE(); \
} \ } \
if ((e) == NULL) { \ if ((e) == NULL) { \
JLI_ReportErrorMessage(JNI_ERROR); \ JLI_ReportErrorMessage(JNI_ERROR); \
goto leave; \ LEAVE(); \
} }
#define CHECK_EXCEPTION_LEAVE(rv) \ #define CHECK_EXCEPTION_LEAVE(rv) \
if ((*env)->ExceptionOccurred(env)) { \ if ((*env)->ExceptionOccurred(env)) { \
JLI_ReportExceptionDescription(env); \ JLI_ReportExceptionDescription(env); \
ret = (rv); \ ret = (rv); \
goto leave; \ LEAVE(); \
} }
int JNICALL int JNICALL
...@@ -349,8 +373,7 @@ JavaMain(void * _args) ...@@ -349,8 +373,7 @@ JavaMain(void * _args)
PrintJavaVersion(env, showVersion); PrintJavaVersion(env, showVersion);
CHECK_EXCEPTION_LEAVE(0); CHECK_EXCEPTION_LEAVE(0);
if (printVersion) { if (printVersion) {
ret = 0; LEAVE();
goto leave;
} }
} }
...@@ -358,7 +381,7 @@ JavaMain(void * _args) ...@@ -358,7 +381,7 @@ JavaMain(void * _args)
if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) {
PrintUsage(env, printXUsage); PrintUsage(env, printXUsage);
CHECK_EXCEPTION_LEAVE(1); CHECK_EXCEPTION_LEAVE(1);
goto leave; LEAVE();
} }
FreeKnownVMs(); /* after last possible PrintUsage() */ FreeKnownVMs(); /* after last possible PrintUsage() */
...@@ -430,30 +453,7 @@ JavaMain(void * _args) ...@@ -430,30 +453,7 @@ JavaMain(void * _args)
* System.exit) will be non-zero if main threw an exception. * System.exit) will be non-zero if main threw an exception.
*/ */
ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
LEAVE();
leave:
/*
* Always detach the main thread so that it appears to have ended when
* the application's main method exits. This will invoke the
* uncaught exception handler machinery if main threw an
* exception. An uncaught exception handler cannot change the
* launcher's return code except by calling System.exit.
*/
if ((*vm)->DetachCurrentThread(vm) != 0) {
JLI_ReportErrorMessage(JVM_ERROR2);
ret = 1;
}
/*
* Wait for all non-daemon threads to end, then destroy the VM.
* This will actually create a trivial new Java waiter thread
* named "DestroyJavaVM", but this will be seen as a different
* thread from the one that executed main, even though they are
* the same C thread. This allows mainThread.join() and
* mainThread.isAlive() to work as expected.
*/
(*vm)->DestroyJavaVM(vm);
return ret;
} }
/* /*
...@@ -1076,15 +1076,17 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile, ...@@ -1076,15 +1076,17 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile,
if (--argc >= 0) { if (--argc >= 0) {
if (jarflag) { if (jarflag) {
*pjarfile = *argv++; *pjarfile = *argv++;
*pclassname = 0; *pclassname = NULL;
} else { } else {
*pjarfile = 0; *pjarfile = NULL;
*pclassname = *argv++; *pclassname = *argv++;
} }
*pargc = argc; *pargc = argc;
*pargv = argv; *pargv = argv;
} }
if (*pjarfile == NULL && *pclassname == NULL) {
*pret = 1;
}
return JNI_TRUE; return JNI_TRUE;
} }
......
/* /*
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -114,13 +114,19 @@ GetApplicationHome(char *buf, jint bufsize); ...@@ -114,13 +114,19 @@ GetApplicationHome(char *buf, jint bufsize);
#define GetArch() GetArchPath(CURRENT_DATA_MODEL) #define GetArch() GetArchPath(CURRENT_DATA_MODEL)
void CreateExecutionEnvironment(int *_argc, /*
char ***_argv, * Different platforms will implement this, here
char jrepath[], * pargc is a pointer to the original argc,
jint so_jrepath, * pargv is a pointer to the original argv,
char jvmpath[], * jrepath is an accessible path to the jre as determined by the call
jint so_jvmpath, * so_jrepath is the length of the buffer jrepath
char **original_argv); * jvmpath is an accessible path to the jvm as determined by the call
* so_jvmpath is the length of the buffer jvmpath
*/
void CreateExecutionEnvironment(int *argc, char ***argv,
char *jrepath, jint so_jrepath,
char *jvmpath, jint so_jvmpath);
/* Reports an error message to stderr or a window as appropriate. */ /* Reports an error message to stderr or a window as appropriate. */
void JLI_ReportErrorMessage(const char * message, ...); void JLI_ReportErrorMessage(const char * message, ...);
......
/* /*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -84,23 +84,6 @@ JLI_MemFree(void *ptr) ...@@ -84,23 +84,6 @@ JLI_MemFree(void *ptr)
free(ptr); free(ptr);
} }
/*
* Makes a copy of arguments
*/
char**
JLI_CopyArgs(int argc, const char **iargv)
{
int i;
char** oargv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1));
for (i = 0 ; i < argc+1 ; i++) {
oargv[i] = (iargv[i] == NULL) ? NULL : JLI_StringDup(iargv[i]);
if (iargv[i] != NULL && JLI_IsTraceLauncher() == JNI_TRUE) {
printf("\targv[%d] = '%s'\n",i,iargv[i]);
}
}
return oargv;
}
/* /*
* debug helpers we use * debug helpers we use
*/ */
......
/* /*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -33,7 +33,6 @@ void *JLI_MemAlloc(size_t size); ...@@ -33,7 +33,6 @@ void *JLI_MemAlloc(size_t size);
void *JLI_MemRealloc(void *ptr, size_t size); void *JLI_MemRealloc(void *ptr, size_t size);
char *JLI_StringDup(const char *s1); char *JLI_StringDup(const char *s1);
void JLI_MemFree(void *ptr); void JLI_MemFree(void *ptr);
char **JLI_CopyArgs(int argc, const char **iargv);
int JLI_StrCCmp(const char *s1, const char* s2); int JLI_StrCCmp(const char *s1, const char* s2);
...@@ -56,10 +55,12 @@ int JLI_StrCCmp(const char *s1, const char* s2); ...@@ -56,10 +55,12 @@ int JLI_StrCCmp(const char *s1, const char* s2);
#include <io.h> #include <io.h>
#define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2)) #define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2))
#define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3)) #define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3))
#define JLI_Snprintf _snprintf
#else #else
#include <unistd.h> #include <unistd.h>
#define JLI_StrCaseCmp(p1, p2) strcasecmp((p1), (p2)) #define JLI_StrCaseCmp(p1, p2) strcasecmp((p1), (p2))
#define JLI_StrNCaseCmp(p1, p2, p3) strncasecmp((p1), (p2), (p3)) #define JLI_StrNCaseCmp(p1, p2, p3) strncasecmp((p1), (p2), (p3))
#define JLI_Snprintf snprintf
#endif /* _WIN32 */ #endif /* _WIN32 */
/* /*
......
/* /*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -39,7 +39,7 @@ class InstanceFinder<T> { ...@@ -39,7 +39,7 @@ class InstanceFinder<T> {
private final Class<? extends T> type; private final Class<? extends T> type;
private final boolean allow; private final boolean allow;
private final String suffix; private final String suffix;
private String[] packages; private volatile String[] packages;
InstanceFinder(Class<? extends T> type, boolean allow, String suffix, String... packages) { InstanceFinder(Class<? extends T> type, boolean allow, String suffix, String... packages) {
this.type = type; this.type = type;
...@@ -49,9 +49,7 @@ class InstanceFinder<T> { ...@@ -49,9 +49,7 @@ class InstanceFinder<T> {
} }
public String[] getPackages() { public String[] getPackages() {
return (this.packages.length > 0) return this.packages.clone();
? this.packages.clone()
: this.packages;
} }
public void setPackages(String... packages) { public void setPackages(String... packages) {
......
/* /*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -118,7 +118,7 @@ public final class MethodFinder extends AbstractFinder<Method> { ...@@ -118,7 +118,7 @@ public final class MethodFinder extends AbstractFinder<Method> {
* @throws NoSuchMethodException if method is not accessible or is not found * @throws NoSuchMethodException if method is not accessible or is not found
* in specified superclass or interface * in specified superclass or interface
*/ */
private static Method findAccessibleMethod(Method method) throws NoSuchMethodException { public static Method findAccessibleMethod(Method method) throws NoSuchMethodException {
Class<?> type = method.getDeclaringClass(); Class<?> type = method.getDeclaringClass();
if (Modifier.isPublic(type.getModifiers())) { if (Modifier.isPublic(type.getModifiers())) {
return method; return method;
......
/* /*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -47,6 +47,7 @@ public final class PersistenceDelegateFinder ...@@ -47,6 +47,7 @@ public final class PersistenceDelegateFinder
} }
public void register(Class<?> type, PersistenceDelegate delegate) { public void register(Class<?> type, PersistenceDelegate delegate) {
synchronized (this.registry) {
if (delegate != null) { if (delegate != null) {
this.registry.put(type, delegate); this.registry.put(type, delegate);
} }
...@@ -54,10 +55,14 @@ public final class PersistenceDelegateFinder ...@@ -54,10 +55,14 @@ public final class PersistenceDelegateFinder
this.registry.remove(type); this.registry.remove(type);
} }
} }
}
@Override @Override
public PersistenceDelegate find(Class<?> type) { public PersistenceDelegate find(Class<?> type) {
PersistenceDelegate delegate = this.registry.get(type); PersistenceDelegate delegate;
synchronized (this.registry) {
delegate = this.registry.get(type);
}
return (delegate != null) ? delegate : super.find(type); return (delegate != null) ? delegate : super.find(type);
} }
} }
/* /*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -64,12 +64,18 @@ public final class PropertyEditorFinder ...@@ -64,12 +64,18 @@ public final class PropertyEditorFinder
} }
public void register(Class<?> type, Class<?> editor) { public void register(Class<?> type, Class<?> editor) {
synchronized (this.registry) {
this.registry.put(type, editor); this.registry.put(type, editor);
} }
}
@Override @Override
public PropertyEditor find(Class<?> type) { public PropertyEditor find(Class<?> type) {
PropertyEditor editor = instantiate(this.registry.get(type), null); Class<?> predefined;
synchronized (this.registry) {
predefined = this.registry.get(type);
}
PropertyEditor editor = instantiate(predefined, null);
if (editor == null) { if (editor == null) {
editor = super.find(type); editor = super.find(type);
if ((editor == null) && (null != type.getEnumConstants())) { if ((editor == null) && (null != type.getEnumConstants())) {
......
...@@ -1440,10 +1440,6 @@ class GTKPainter extends SynthPainter { ...@@ -1440,10 +1440,6 @@ class GTKPainter extends SynthPainter {
} }
} }
public Insets getBorderInsets(Component c) {
return getBorderInsets(c, null);
}
public Insets getBorderInsets(Component c, Insets i) { public Insets getBorderInsets(Component c, Insets i) {
SynthContext context = getContext(c); SynthContext context = getContext(c);
......
/* /*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -271,7 +271,9 @@ public class MotifFileChooserUI extends BasicFileChooserUI { ...@@ -271,7 +271,9 @@ public class MotifFileChooserUI extends BasicFileChooserUI {
} }
public void uninstallUI(JComponent c) { public void uninstallUI(JComponent c) {
getFileChooser().removeAll(); c.removePropertyChangeListener(filterComboBoxModel);
approveButton.removeActionListener(getApproveSelectionAction());
filenameTextField.removeActionListener(getApproveSelectionAction());
super.uninstallUI(c); super.uninstallUI(c);
} }
...@@ -515,6 +517,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI { ...@@ -515,6 +517,7 @@ public class MotifFileChooserUI extends BasicFileChooserUI {
public void uninstallComponents(JFileChooser fc) { public void uninstallComponents(JFileChooser fc) {
fc.removeAll(); fc.removeAll();
bottomPanel = null;
if (filterComboBoxModel != null) { if (filterComboBoxModel != null) {
fc.removePropertyChangeListener(filterComboBoxModel); fc.removePropertyChangeListener(filterComboBoxModel);
} }
......
...@@ -61,77 +61,31 @@ import sun.awt.EventQueueDelegate; ...@@ -61,77 +61,31 @@ import sun.awt.EventQueueDelegate;
* @since 1.1 * @since 1.1
*/ */
class EventDispatchThread extends Thread { class EventDispatchThread extends Thread {
private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread"); private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
private EventQueue theQueue; private EventQueue theQueue;
private boolean doDispatch = true; private boolean doDispatch = true;
private boolean threadDeathCaught = false;
private static final int ANY_EVENT = -1; private static final int ANY_EVENT = -1;
private Vector<EventFilter> eventFilters = new Vector<EventFilter>(); private Vector<EventFilter> eventFilters = new Vector<EventFilter>();
// used in handleException
private int modalFiltersCount = 0;
EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
super(group, name); super(group, name);
theQueue = queue; setEventQueue(queue);
}
void stopDispatchingImpl(boolean wait) {
// Note: We stop dispatching via a flag rather than using
// Thread.interrupt() because we can't guarantee that the wait()
// we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
StopDispatchEvent stopEvent = new StopDispatchEvent();
// wait for the dispatcher to complete
if (Thread.currentThread() != this) {
// fix 4122683, 4128923
// Post an empty event to ensure getNextEvent is unblocked
//
// We have to use postEventPrivate instead of postEvent because
// EventQueue.pop calls EventDispatchThread.stopDispatching.
// Calling SunToolkit.flushPendingEvents in this case could
// lead to deadlock.
theQueue.postEventPrivate(stopEvent);
if (wait) {
try {
join();
} catch(InterruptedException e) {
}
}
} else {
stopEvent.dispatch();
}
theQueue.detachDispatchThread(this, false);
}
public void stopDispatching() {
stopDispatchingImpl(true);
}
public void stopDispatchingLater() {
stopDispatchingImpl(false);
} }
class StopDispatchEvent extends AWTEvent implements ActiveEvent {
/* /*
* serialVersionUID * Must be called on EDT only, that's why no synchronization
*/ */
static final long serialVersionUID = -3692158172100730735L; public void stopDispatching() {
public StopDispatchEvent() {
super(EventDispatchThread.this,0);
}
public void dispatch() {
doDispatch = false; doDispatch = false;
} }
}
public void run() { public void run() {
while (true) {
try { try {
pumpEvents(new Conditional() { pumpEvents(new Conditional() {
public boolean evaluate() { public boolean evaluate() {
...@@ -139,7 +93,11 @@ class EventDispatchThread extends Thread { ...@@ -139,7 +93,11 @@ class EventDispatchThread extends Thread {
} }
}); });
} finally { } finally {
theQueue.detachDispatchThread(this, true); EventQueue eq = getEventQueue();
if (eq.detachDispatchThread(this) || threadDeathCaught) {
break;
}
}
} }
} }
...@@ -190,7 +148,6 @@ class EventDispatchThread extends Thread { ...@@ -190,7 +148,6 @@ class EventDispatchThread extends Thread {
} }
} }
eventFilters.add(k, filter); eventFilters.add(k, filter);
modalFiltersCount++;
} else { } else {
eventFilters.add(filter); eventFilters.add(filter);
} }
...@@ -200,28 +157,25 @@ class EventDispatchThread extends Thread { ...@@ -200,28 +157,25 @@ class EventDispatchThread extends Thread {
void removeEventFilter(EventFilter filter) { void removeEventFilter(EventFilter filter) {
synchronized (eventFilters) { synchronized (eventFilters) {
if (eventFilters.contains(filter)) {
if (filter instanceof ModalEventFilter) {
modalFiltersCount--;
}
eventFilters.remove(filter); eventFilters.remove(filter);
} }
} }
}
boolean pumpOneEventForFilters(int id) { boolean pumpOneEventForFilters(int id) {
AWTEvent event = null;
boolean eventOK = false;
try { try {
AWTEvent event; EventQueue eq = null;
boolean eventOK; EventQueueDelegate.Delegate delegate = null;
EventQueueDelegate.Delegate delegate =
EventQueueDelegate.getDelegate();
do { do {
// EventQueue may change during the dispatching
eq = getEventQueue();
delegate = EventQueueDelegate.getDelegate();
if (delegate != null && id == ANY_EVENT) { if (delegate != null && id == ANY_EVENT) {
event = delegate.getNextEvent(theQueue); event = delegate.getNextEvent(eq);
} else { } else {
event = (id == ANY_EVENT) event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
? theQueue.getNextEvent()
: theQueue.getNextEvent(id);
} }
eventOK = true; eventOK = true;
...@@ -252,13 +206,15 @@ class EventDispatchThread extends Thread { ...@@ -252,13 +206,15 @@ class EventDispatchThread extends Thread {
if (delegate != null) { if (delegate != null) {
handle = delegate.beforeDispatch(event); handle = delegate.beforeDispatch(event);
} }
theQueue.dispatchEvent(event); eq.dispatchEvent(event);
if (delegate != null) { if (delegate != null) {
delegate.afterDispatch(event, handle); delegate.afterDispatch(event, handle);
} }
return true; return true;
} }
catch (ThreadDeath death) { catch (ThreadDeath death) {
threadDeathCaught = true;
return false; return false;
} }
...@@ -267,12 +223,10 @@ class EventDispatchThread extends Thread { ...@@ -267,12 +223,10 @@ class EventDispatchThread extends Thread {
// Threads in the AppContext // Threads in the AppContext
} }
// Can get and throw only unchecked exceptions catch (Throwable e) {
catch (RuntimeException e) {
processException(e);
} catch (Error e) {
processException(e); processException(e);
} }
return true; return true;
} }
...@@ -281,14 +235,14 @@ class EventDispatchThread extends Thread { ...@@ -281,14 +235,14 @@ class EventDispatchThread extends Thread {
eventLog.fine("Processing exception: " + e); eventLog.fine("Processing exception: " + e);
} }
getUncaughtExceptionHandler().uncaughtException(this, e); getUncaughtExceptionHandler().uncaughtException(this, e);
// don't rethrow the exception to avoid EDT recreation
} }
boolean isDispatching(EventQueue eq) { public synchronized EventQueue getEventQueue() {
return theQueue.equals(eq); return theQueue;
}
public synchronized void setEventQueue(EventQueue eq) {
theQueue = eq;
} }
EventQueue getEventQueue() { return theQueue; }
private static class HierarchyEventFilter implements EventFilter { private static class HierarchyEventFilter implements EventFilter {
private Component modalComponent; private Component modalComponent;
......
...@@ -138,6 +138,15 @@ public class EventQueue { ...@@ -138,6 +138,15 @@ public class EventQueue {
private final Lock pushPopLock; private final Lock pushPopLock;
private final Condition pushPopCond; private final Condition pushPopCond;
/*
* Dummy runnable to wake up EDT from getNextEvent() after
push/pop is performed
*/
private final static Runnable dummyRunnable = new Runnable() {
public void run() {
}
};
private EventDispatchThread dispatchThread; private EventDispatchThread dispatchThread;
private final ThreadGroup threadGroup = private final ThreadGroup threadGroup =
...@@ -219,22 +228,22 @@ public class EventQueue { ...@@ -219,22 +228,22 @@ public class EventQueue {
* @param theEvent an instance of <code>java.awt.AWTEvent</code>, * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
* or a subclass of it * or a subclass of it
*/ */
final void postEventPrivate(AWTEvent theEvent) { private final void postEventPrivate(AWTEvent theEvent) {
theEvent.isPosted = true; theEvent.isPosted = true;
pushPopLock.lock(); pushPopLock.lock();
try { try {
if (dispatchThread == null && nextQueue == null) { if (nextQueue != null) {
// Forward the event to the top of EventQueue stack
nextQueue.postEventPrivate(theEvent);
return;
}
if (dispatchThread == null) {
if (theEvent.getSource() == AWTAutoShutdown.getInstance()) { if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
return; return;
} else { } else {
initDispatchThread(); initDispatchThread();
} }
} }
if (nextQueue != null) {
// Forward event to top of EventQueue stack.
nextQueue.postEventPrivate(theEvent);
return;
}
postEvent(theEvent, getPriority(theEvent)); postEvent(theEvent, getPriority(theEvent));
} finally { } finally {
pushPopLock.unlock(); pushPopLock.unlock();
...@@ -242,29 +251,20 @@ public class EventQueue { ...@@ -242,29 +251,20 @@ public class EventQueue {
} }
private static int getPriority(AWTEvent theEvent) { private static int getPriority(AWTEvent theEvent) {
if (theEvent instanceof PeerEvent && if (theEvent instanceof PeerEvent) {
(((PeerEvent)theEvent).getFlags() & PeerEvent peerEvent = (PeerEvent)theEvent;
PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
{
return ULTIMATE_PRIORITY; return ULTIMATE_PRIORITY;
} }
if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
if (theEvent instanceof PeerEvent &&
(((PeerEvent)theEvent).getFlags() &
PeerEvent.PRIORITY_EVENT) != 0)
{
return HIGH_PRIORITY; return HIGH_PRIORITY;
} }
if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
if (theEvent instanceof PeerEvent &&
(((PeerEvent)theEvent).getFlags() &
PeerEvent.LOW_PRIORITY_EVENT) != 0)
{
return LOW_PRIORITY; return LOW_PRIORITY;
} }
}
int id = theEvent.getID(); int id = theEvent.getID();
if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) { if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
return LOW_PRIORITY; return LOW_PRIORITY;
} }
return NORM_PRIORITY; return NORM_PRIORITY;
...@@ -501,6 +501,22 @@ public class EventQueue { ...@@ -501,6 +501,22 @@ public class EventQueue {
SunToolkit.flushPendingEvents(); SunToolkit.flushPendingEvents();
pushPopLock.lock(); pushPopLock.lock();
try { try {
AWTEvent event = getNextEventPrivate();
if (event != null) {
return event;
}
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
pushPopCond.await();
} finally {
pushPopLock.unlock();
}
} while(true);
}
/*
* Must be called under the lock. Doesn't call flushPendingEvents()
*/
AWTEvent getNextEventPrivate() throws InterruptedException {
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
if (queues[i].head != null) { if (queues[i].head != null) {
EventQueueItem entry = queues[i].head; EventQueueItem entry = queues[i].head;
...@@ -512,12 +528,7 @@ public class EventQueue { ...@@ -512,12 +528,7 @@ public class EventQueue {
return entry.event; return entry.event;
} }
} }
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread); return null;
pushPopCond.await();
} finally {
pushPopLock.unlock();
}
} while(true);
} }
AWTEvent getNextEvent(int id) throws InterruptedException { AWTEvent getNextEvent(int id) throws InterruptedException {
...@@ -659,7 +670,9 @@ public class EventQueue { ...@@ -659,7 +670,9 @@ public class EventQueue {
dispatchThread.stopDispatching(); dispatchThread.stopDispatching();
} }
} else { } else {
System.err.println("unable to dispatch event: " + event); if (eventLog.isLoggable(PlatformLogger.FINE)) {
eventLog.fine("Unable to dispatch event: " + event);
}
} }
} }
...@@ -761,15 +774,23 @@ public class EventQueue { ...@@ -761,15 +774,23 @@ public class EventQueue {
pushPopLock.lock(); pushPopLock.lock();
try { try {
EventQueue toPush = this; EventQueue topQueue = this;
while (toPush.nextQueue != null) { while (topQueue.nextQueue != null) {
toPush = toPush.nextQueue; topQueue = topQueue.nextQueue;
}
if ((topQueue.dispatchThread != null) &&
(topQueue.dispatchThread.getEventQueue() == this))
{
newEventQueue.dispatchThread = topQueue.dispatchThread;
topQueue.dispatchThread.setEventQueue(newEventQueue);
} }
// Transfer all events forward to new EventQueue. // Transfer all events forward to new EventQueue.
while (toPush.peekEvent() != null) { while (topQueue.peekEvent() != null) {
try { try {
newEventQueue.postEventPrivate(toPush.getNextEvent()); // Use getNextEventPrivate() as it doesn't call flushPendingEvents()
newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
if (eventLog.isLoggable(PlatformLogger.FINE)) { if (eventLog.isLoggable(PlatformLogger.FINE)) {
eventLog.fine("Interrupted push", ie); eventLog.fine("Interrupted push", ie);
...@@ -777,28 +798,21 @@ public class EventQueue { ...@@ -777,28 +798,21 @@ public class EventQueue {
} }
} }
newEventQueue.previousQueue = toPush; // Wake up EDT waiting in getNextEvent(), so it can
// pick up a new EventQueue. Post the waking event before
// topQueue.nextQueue is assigned, otherwise the event would
// go newEventQueue
topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
/* newEventQueue.previousQueue = topQueue;
* Stop the event dispatch thread associated with the currently topQueue.nextQueue = newEventQueue;
* active event queue, so that after the new queue is pushed
* on the top this event dispatch thread won't prevent AWT from
* being automatically shut down.
* Use stopDispatchingLater() to avoid deadlock: stopDispatching()
* waits for the dispatch thread to exit, which in turn waits
* for the lock in EQ.detachDispatchThread(), which is hold by
* this method.
*/
if (toPush.dispatchThread != null) {
toPush.dispatchThread.stopDispatchingLater();
}
toPush.nextQueue = newEventQueue;
AppContext appContext = AppContext.getAppContext(); AppContext appContext = AppContext.getAppContext();
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == toPush) { if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue); appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
} }
pushPopCond.signalAll();
} finally { } finally {
pushPopLock.unlock(); pushPopLock.unlock();
} }
...@@ -822,44 +836,51 @@ public class EventQueue { ...@@ -822,44 +836,51 @@ public class EventQueue {
eventLog.fine("EventQueue.pop(" + this + ")"); eventLog.fine("EventQueue.pop(" + this + ")");
} }
EventDispatchThread dt = null;
pushPopLock.lock(); pushPopLock.lock();
try { try {
EventQueue toPop = this; EventQueue topQueue = this;
while (toPop.nextQueue != null) { while (topQueue.nextQueue != null) {
toPop = toPop.nextQueue; topQueue = topQueue.nextQueue;
} }
EventQueue prev = toPop.previousQueue; EventQueue prevQueue = topQueue.previousQueue;
if (prev == null) { if (prevQueue == null) {
throw new EmptyStackException(); throw new EmptyStackException();
} }
toPop.previousQueue = null;
topQueue.previousQueue = null;
prevQueue.nextQueue = null;
// Transfer all events back to previous EventQueue. // Transfer all events back to previous EventQueue.
prev.nextQueue = null; while (topQueue.peekEvent() != null) {
while (toPop.peekEvent() != null) {
try { try {
prev.postEventPrivate(toPop.getNextEvent()); prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
if (eventLog.isLoggable(PlatformLogger.FINE)) { if (eventLog.isLoggable(PlatformLogger.FINE)) {
eventLog.fine("Interrupted pop", ie); eventLog.fine("Interrupted pop", ie);
} }
} }
} }
if ((topQueue.dispatchThread != null) &&
(topQueue.dispatchThread.getEventQueue() == this))
{
prevQueue.dispatchThread = topQueue.dispatchThread;
topQueue.dispatchThread.setEventQueue(prevQueue);
}
AppContext appContext = AppContext.getAppContext(); AppContext appContext = AppContext.getAppContext();
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) { if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
appContext.put(AppContext.EVENT_QUEUE_KEY, prev); appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
} }
dt = toPop.dispatchThread; // Wake up EDT waiting in getNextEvent(), so it can
// pick up a new EventQueue
topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
pushPopCond.signalAll();
} finally { } finally {
pushPopLock.unlock(); pushPopLock.unlock();
} }
if (dt != null) {
dt.stopDispatching(); // Must be done outside synchronized
// block to avoid possible deadlock
}
} }
/** /**
...@@ -907,9 +928,9 @@ public class EventQueue { ...@@ -907,9 +928,9 @@ public class EventQueue {
try { try {
AppContext appContext = AppContext.getAppContext(); AppContext appContext = AppContext.getAppContext();
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) { if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
dispatchThread = (EventDispatchThread) dispatchThread = AccessController.doPrivileged(
AccessController.doPrivileged(new PrivilegedAction() { new PrivilegedAction<EventDispatchThread>() {
public Object run() { public EventDispatchThread run() {
EventDispatchThread t = EventDispatchThread t =
new EventDispatchThread(threadGroup, new EventDispatchThread(threadGroup,
name, name,
...@@ -919,7 +940,8 @@ public class EventQueue { ...@@ -919,7 +940,8 @@ public class EventQueue {
t.setDaemon(false); t.setDaemon(false);
return t; return t;
} }
}); }
);
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
dispatchThread.start(); dispatchThread.start();
} }
...@@ -928,7 +950,7 @@ public class EventQueue { ...@@ -928,7 +950,7 @@ public class EventQueue {
} }
} }
final void detachDispatchThread(EventDispatchThread edt, boolean restart) { final boolean detachDispatchThread(EventDispatchThread edt) {
/* /*
* This synchronized block is to secure that the event dispatch * This synchronized block is to secure that the event dispatch
* thread won't die in the middle of posting a new event to the * thread won't die in the middle of posting a new event to the
...@@ -939,26 +961,21 @@ public class EventQueue { ...@@ -939,26 +961,21 @@ public class EventQueue {
*/ */
pushPopLock.lock(); pushPopLock.lock();
try { try {
EventDispatchThread oldDispatchThread = dispatchThread; if (edt == dispatchThread) {
if (dispatchThread == edt) {
dispatchThread = null;
}
if (restart) {
/* /*
* Event dispatch thread dies in case of an uncaught exception. * Don't detach the thread if any events are pending. Not
* A new event dispatch thread for this queue will be started * sure if it's a possible scenario, though.
* only if a new event is posted to it. In case if no more
* events are posted after this thread died all events that
* currently are in the queue will never be dispatched.
* *
* Fix for 4648733. Check both the associated java event * Fix for 4648733. Check both the associated java event
* queue and the PostEventQueue. * queue and the PostEventQueue.
*/ */
if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) { if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
initDispatchThread(); return false;
} }
AWTAutoShutdown.getInstance().notifyThreadFree(oldDispatchThread); dispatchThread = null;
} }
AWTAutoShutdown.getInstance().notifyThreadFree(edt);
return true;
} finally { } finally {
pushPopLock.unlock(); pushPopLock.unlock();
} }
......
...@@ -194,13 +194,8 @@ public class Encoder { ...@@ -194,13 +194,8 @@ public class Encoder {
* @see java.beans.BeanInfo#getBeanDescriptor * @see java.beans.BeanInfo#getBeanDescriptor
*/ */
public PersistenceDelegate getPersistenceDelegate(Class<?> type) { public PersistenceDelegate getPersistenceDelegate(Class<?> type) {
synchronized (this.finder) {
PersistenceDelegate pd = this.finder.find(type); PersistenceDelegate pd = this.finder.find(type);
if (pd != null) { return (pd != null) ? pd : MetaData.getPersistenceDelegate(type);
return pd;
}
}
return MetaData.getPersistenceDelegate(type);
} }
/** /**
...@@ -214,10 +209,8 @@ public class Encoder { ...@@ -214,10 +209,8 @@ public class Encoder {
* @see java.beans.BeanInfo#getBeanDescriptor * @see java.beans.BeanInfo#getBeanDescriptor
*/ */
public void setPersistenceDelegate(Class<?> type, PersistenceDelegate delegate) { public void setPersistenceDelegate(Class<?> type, PersistenceDelegate delegate) {
synchronized (this.finder) {
this.finder.register(type, delegate); this.finder.register(type, delegate);
} }
}
/** /**
* Removes the entry for this instance, returning the old entry. * Removes the entry for this instance, returning the old entry.
......
...@@ -27,6 +27,7 @@ package java.beans; ...@@ -27,6 +27,7 @@ package java.beans;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/** /**
* An EventSetDescriptor describes a group of events that a given Java * An EventSetDescriptor describes a group of events that a given Java
...@@ -175,10 +176,8 @@ public class EventSetDescriptor extends FeatureDescriptor { ...@@ -175,10 +176,8 @@ public class EventSetDescriptor extends FeatureDescriptor {
setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1)); setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1));
// Be more forgiving of not finding the getListener method. // Be more forgiving of not finding the getListener method.
Method method = Introspector.findMethod(sourceClass, if (getListenerMethodName != null) {
getListenerMethodName, 0); setGetListenerMethod(Introspector.findInstanceMethod(sourceClass, getListenerMethodName));
if (method != null) {
setGetListenerMethod(method);
} }
} }
...@@ -188,7 +187,7 @@ public class EventSetDescriptor extends FeatureDescriptor { ...@@ -188,7 +187,7 @@ public class EventSetDescriptor extends FeatureDescriptor {
return null; return null;
} }
Method method = Introspector.findMethod(cls, name, args); Method method = Introspector.findMethod(cls, name, args);
if (method == null) { if ((method == null) || Modifier.isStatic(method.getModifiers())) {
throw new IntrospectionException("Method not found: " + name + throw new IntrospectionException("Method not found: " + name +
" on class " + cls.getName()); " on class " + cls.getName());
} }
......
...@@ -189,16 +189,11 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor { ...@@ -189,16 +189,11 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor {
indexedReadMethodName = Introspector.GET_PREFIX + getBaseName(); indexedReadMethodName = Introspector.GET_PREFIX + getBaseName();
} }
} }
indexedReadMethod = Introspector.findInstanceMethod(cls, indexedReadMethodName, int.class);
Class[] args = { int.class };
indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName,
1, args);
if (indexedReadMethod == null) { if (indexedReadMethod == null) {
// no "is" method, so look for a "get" method. // no "is" method, so look for a "get" method.
indexedReadMethodName = Introspector.GET_PREFIX + getBaseName(); indexedReadMethodName = Introspector.GET_PREFIX + getBaseName();
indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, indexedReadMethod = Introspector.findInstanceMethod(cls, indexedReadMethodName, int.class);
1, args);
} }
setIndexedReadMethod0(indexedReadMethod); setIndexedReadMethod0(indexedReadMethod);
} }
...@@ -270,8 +265,7 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor { ...@@ -270,8 +265,7 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor {
if (indexedWriteMethodName == null) { if (indexedWriteMethodName == null) {
indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName(); indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName();
} }
indexedWriteMethod = Introspector.findMethod(cls, indexedWriteMethodName, indexedWriteMethod = Introspector.findInstanceMethod(cls, indexedWriteMethodName, int.class, type);
2, (type == null) ? null : new Class[] { int.class, type });
if (indexedWriteMethod != null) { if (indexedWriteMethod != null) {
if (!indexedWriteMethod.getReturnType().equals(void.class)) { if (!indexedWriteMethod.getReturnType().equals(void.class)) {
indexedWriteMethod = null; indexedWriteMethod = null;
......
...@@ -28,6 +28,7 @@ package java.beans; ...@@ -28,6 +28,7 @@ package java.beans;
import com.sun.beans.WeakCache; import com.sun.beans.WeakCache;
import com.sun.beans.finder.BeanInfoFinder; import com.sun.beans.finder.BeanInfoFinder;
import com.sun.beans.finder.ClassFinder; import com.sun.beans.finder.ClassFinder;
import com.sun.beans.finder.MethodFinder;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
...@@ -157,21 +158,23 @@ public class Introspector { ...@@ -157,21 +158,23 @@ public class Introspector {
if (!ReflectUtil.isPackageAccessible(beanClass)) { if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo(); return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
} }
Map<Class<?>, BeanInfo> beanInfoCache;
BeanInfo beanInfo;
synchronized (BEANINFO_CACHE) { synchronized (BEANINFO_CACHE) {
Map<Class<?>, BeanInfo> beanInfoCache = beanInfoCache = (Map<Class<?>, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE);
(Map<Class<?>, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE);
if (beanInfoCache == null) { if (beanInfoCache == null) {
beanInfoCache = new WeakHashMap<Class<?>, BeanInfo>(); beanInfoCache = new WeakHashMap<Class<?>, BeanInfo>();
AppContext.getAppContext().put(BEANINFO_CACHE, beanInfoCache); AppContext.getAppContext().put(BEANINFO_CACHE, beanInfoCache);
} }
BeanInfo beanInfo = beanInfoCache.get(beanClass); beanInfo = beanInfoCache.get(beanClass);
}
if (beanInfo == null) { if (beanInfo == null) {
beanInfo = (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo(); beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
synchronized (BEANINFO_CACHE) {
beanInfoCache.put(beanClass, beanInfo); beanInfoCache.put(beanClass, beanInfo);
} }
return beanInfo;
} }
return beanInfo;
} }
/** /**
...@@ -301,10 +304,7 @@ public class Introspector { ...@@ -301,10 +304,7 @@ public class Introspector {
*/ */
public static String[] getBeanInfoSearchPath() { public static String[] getBeanInfoSearchPath() {
BeanInfoFinder finder = getFinder(); return getFinder().getPackages();
synchronized (finder) {
return finder.getPackages();
}
} }
/** /**
...@@ -328,10 +328,7 @@ public class Introspector { ...@@ -328,10 +328,7 @@ public class Introspector {
if (sm != null) { if (sm != null) {
sm.checkPropertiesAccess(); sm.checkPropertiesAccess();
} }
BeanInfoFinder finder = getFinder(); getFinder().setPackages(path);
synchronized (finder) {
finder.setPackages(path);
}
} }
...@@ -453,10 +450,7 @@ public class Introspector { ...@@ -453,10 +450,7 @@ public class Introspector {
* @return Instance of an explicit BeanInfo class or null if one isn't found. * @return Instance of an explicit BeanInfo class or null if one isn't found.
*/ */
private static BeanInfo findExplicitBeanInfo(Class beanClass) { private static BeanInfo findExplicitBeanInfo(Class beanClass) {
BeanInfoFinder finder = getFinder(); return getFinder().find(beanClass);
synchronized (finder) {
return finder.find(beanClass);
}
} }
/** /**
...@@ -849,8 +843,8 @@ public class Introspector { ...@@ -849,8 +843,8 @@ public class Introspector {
Method read = result.getReadMethod(); Method read = result.getReadMethod();
if (read == null && write != null) { if (read == null && write != null) {
read = findMethod(result.getClass0(), read = findInstanceMethod(result.getClass0(),
GET_PREFIX + NameGenerator.capitalize(result.getName()), 0); GET_PREFIX + NameGenerator.capitalize(result.getName()));
if (read != null) { if (read != null) {
try { try {
result.setReadMethod(read); result.setReadMethod(read);
...@@ -860,9 +854,9 @@ public class Introspector { ...@@ -860,9 +854,9 @@ public class Introspector {
} }
} }
if (write == null && read != null) { if (write == null && read != null) {
write = findMethod(result.getClass0(), write = findInstanceMethod(result.getClass0(),
SET_PREFIX + NameGenerator.capitalize(result.getName()), 1, SET_PREFIX + NameGenerator.capitalize(result.getName()),
new Class[] { FeatureDescriptor.getReturnType(result.getClass0(), read) }); FeatureDescriptor.getReturnType(result.getClass0(), read));
if (write != null) { if (write != null) {
try { try {
result.setWriteMethod(write); result.setWriteMethod(write);
...@@ -1286,90 +1280,27 @@ public class Introspector { ...@@ -1286,90 +1280,27 @@ public class Introspector {
// Package private support methods. // Package private support methods.
//====================================================================== //======================================================================
/** static Method findMethod(Class<?> type, String name, int args) {
* Internal support for finding a target methodName with a given for (Method method : type.getMethods()) {
* parameter list on a given class. if (method.getName().equals(name) && (args == method.getParameterTypes().length)) {
*/ try {
private static Method internalFindMethod(Class start, String methodName, return MethodFinder.findAccessibleMethod(method);
int argCount, Class args[]) {
// For overriden methods we need to find the most derived version.
// So we start with the given class and walk up the superclass chain.
Method method = null;
for (Class cl = start; cl != null; cl = cl.getSuperclass()) {
Method methods[] = getPublicDeclaredMethods(cl);
for (int i = 0; i < methods.length; i++) {
method = methods[i];
if (method == null) {
continue;
}
// make sure method signature matches.
Class params[] = FeatureDescriptor.getParameterTypes(start, method);
if (method.getName().equals(methodName) &&
params.length == argCount) {
if (args != null) {
boolean different = false;
if (argCount > 0) {
for (int j = 0; j < argCount; j++) {
if (params[j] != args[j]) {
different = true;
continue;
}
}
if (different) {
continue;
}
}
}
return method;
}
} }
catch (NoSuchMethodException exception) {
// continue search for a method with the specified count of parameters
} }
method = null;
// Now check any inherited interfaces. This is necessary both when
// the argument class is itself an interface, and when the argument
// class is an abstract class.
Class ifcs[] = start.getInterfaces();
for (int i = 0 ; i < ifcs.length; i++) {
// Note: The original implementation had both methods calling
// the 3 arg method. This is preserved but perhaps it should
// pass the args array instead of null.
method = internalFindMethod(ifcs[i], methodName, argCount, null);
if (method != null) {
break;
} }
} }
return method; return null;
} }
/** static Method findInstanceMethod(Class<?> type, String name, Class<?>... args) {
* Find a target methodName on a given class. try {
*/ return MethodFinder.findInstanceMethod(type, name, args);
static Method findMethod(Class cls, String methodName, int argCount) {
return findMethod(cls, methodName, argCount, null);
} }
catch (NoSuchMethodException exception) {
/**
* Find a target methodName with specific parameter list on a given class.
* <p>
* Used in the contructors of the EventSetDescriptor,
* PropertyDescriptor and the IndexedPropertyDescriptor.
* <p>
* @param cls The Class object on which to retrieve the method.
* @param methodName Name of the method.
* @param argCount Number of arguments for the desired method.
* @param args Array of argument types for the method.
* @return the method or null if not found
*/
static Method findMethod(Class cls, String methodName, int argCount,
Class args[]) {
if (methodName == null) {
return null; return null;
} }
return internalFindMethod(cls, methodName, argCount, args);
} }
/** /**
......
...@@ -82,21 +82,21 @@ public class MethodDescriptor extends FeatureDescriptor { ...@@ -82,21 +82,21 @@ public class MethodDescriptor extends FeatureDescriptor {
Method method = getMethod0(); Method method = getMethod0();
if (method == null) { if (method == null) {
Class cls = getClass0(); Class cls = getClass0();
if (cls != null) { String name = getName();
if ((cls != null) && (name != null)) {
Class[] params = getParams(); Class[] params = getParams();
if (params == null) { if (params == null) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
// Find methods for up to 2 params. We are guessing here. // Find methods for up to 2 params. We are guessing here.
// This block should never execute unless the classloader // This block should never execute unless the classloader
// that loaded the argument classes disappears. // that loaded the argument classes disappears.
method = Introspector.findMethod(cls, getName(), i, null); method = Introspector.findMethod(cls, name, i);
if (method != null) { if (method != null) {
break; break;
} }
} }
} else { } else {
method = Introspector.findMethod(cls, getName(), method = Statement.getMethod(cls, name, params);
params.length, params);
} }
setMethod(method); setMethod(method);
} }
......
...@@ -112,9 +112,7 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -112,9 +112,7 @@ public class PropertyDescriptor extends FeatureDescriptor {
// If this class or one of its base classes allow PropertyChangeListener, // If this class or one of its base classes allow PropertyChangeListener,
// then we assume that any properties we discover are "bound". // then we assume that any properties we discover are "bound".
// See Introspector.getTargetPropertyInfo() method. // See Introspector.getTargetPropertyInfo() method.
String name = "addPropertyChangeListener"; this.bound = null != Introspector.findInstanceMethod(beanClass, "addPropertyChangeListener", PropertyChangeListener.class);
Class[] args = {PropertyChangeListener.class};
this.bound = (null != Introspector.findMethod(beanClass, name, args.length, args));
} }
/** /**
...@@ -225,10 +223,10 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -225,10 +223,10 @@ public class PropertyDescriptor extends FeatureDescriptor {
// property type is. For booleans, there can be "is" and "get" // property type is. For booleans, there can be "is" and "get"
// methods. If an "is" method exists, this is the official // methods. If an "is" method exists, this is the official
// reader method so look for this one first. // reader method so look for this one first.
readMethod = Introspector.findMethod(cls, readMethodName, 0); readMethod = Introspector.findInstanceMethod(cls, readMethodName);
if (readMethod == null) { if (readMethod == null) {
readMethodName = Introspector.GET_PREFIX + getBaseName(); readMethodName = Introspector.GET_PREFIX + getBaseName();
readMethod = Introspector.findMethod(cls, readMethodName, 0); readMethod = Introspector.findInstanceMethod(cls, readMethodName);
} }
try { try {
setReadMethod(readMethod); setReadMethod(readMethod);
...@@ -293,8 +291,7 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -293,8 +291,7 @@ public class PropertyDescriptor extends FeatureDescriptor {
writeMethodName = Introspector.SET_PREFIX + getBaseName(); writeMethodName = Introspector.SET_PREFIX + getBaseName();
} }
writeMethod = Introspector.findMethod(cls, writeMethodName, 1, writeMethod = Introspector.findInstanceMethod(cls, writeMethodName, type);
(type == null) ? null : new Class[] { type });
if (writeMethod != null) { if (writeMethod != null) {
if (!writeMethod.getReturnType().equals(void.class)) { if (!writeMethod.getReturnType().equals(void.class)) {
writeMethod = null; writeMethod = null;
......
/* /*
* Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -81,10 +81,7 @@ public class PropertyEditorManager { ...@@ -81,10 +81,7 @@ public class PropertyEditorManager {
if (sm != null) { if (sm != null) {
sm.checkPropertiesAccess(); sm.checkPropertiesAccess();
} }
PropertyEditorFinder finder = getFinder(); getFinder().register(targetType, editorClass);
synchronized (finder) {
finder.register(targetType, editorClass);
}
} }
/** /**
...@@ -95,10 +92,7 @@ public class PropertyEditorManager { ...@@ -95,10 +92,7 @@ public class PropertyEditorManager {
* The result is null if no suitable editor can be found. * The result is null if no suitable editor can be found.
*/ */
public static PropertyEditor findEditor(Class<?> targetType) { public static PropertyEditor findEditor(Class<?> targetType) {
PropertyEditorFinder finder = getFinder(); return getFinder().find(targetType);
synchronized (finder) {
return finder.find(targetType);
}
} }
/** /**
...@@ -110,10 +104,7 @@ public class PropertyEditorManager { ...@@ -110,10 +104,7 @@ public class PropertyEditorManager {
* e.g. Sun implementation initially sets to {"sun.beans.editors"}. * e.g. Sun implementation initially sets to {"sun.beans.editors"}.
*/ */
public static String[] getEditorSearchPath() { public static String[] getEditorSearchPath() {
PropertyEditorFinder finder = getFinder(); return getFinder().getPackages();
synchronized (finder) {
return finder.getPackages();
}
} }
/** /**
...@@ -134,10 +125,7 @@ public class PropertyEditorManager { ...@@ -134,10 +125,7 @@ public class PropertyEditorManager {
if (sm != null) { if (sm != null) {
sm.checkPropertiesAccess(); sm.checkPropertiesAccess();
} }
PropertyEditorFinder finder = getFinder(); getFinder().setPackages(path);
synchronized (finder) {
finder.setPackages(path);
}
} }
private static PropertyEditorFinder getFinder() { private static PropertyEditorFinder getFinder() {
......
...@@ -60,7 +60,7 @@ import org.xml.sax.helpers.DefaultHandler; ...@@ -60,7 +60,7 @@ import org.xml.sax.helpers.DefaultHandler;
* *
* @author Philip Milne * @author Philip Milne
*/ */
public class XMLDecoder { public class XMLDecoder implements AutoCloseable {
private final DocumentHandler handler = new DocumentHandler(); private final DocumentHandler handler = new DocumentHandler();
private final InputSource input; private final InputSource input;
private Object owner; private Object owner;
......
...@@ -204,7 +204,7 @@ import java.nio.charset.UnsupportedCharsetException; ...@@ -204,7 +204,7 @@ import java.nio.charset.UnsupportedCharsetException;
* *
* @author Philip Milne * @author Philip Milne
*/ */
public class XMLEncoder extends Encoder { public class XMLEncoder extends Encoder implements AutoCloseable {
private final CharsetEncoder encoder; private final CharsetEncoder encoder;
private final String charset; private final String charset;
......
...@@ -41,51 +41,39 @@ class Bits { ...@@ -41,51 +41,39 @@ class Bits {
} }
static char getChar(byte[] b, int off) { static char getChar(byte[] b, int off) {
return (char) (((b[off + 1] & 0xFF) << 0) + return (char) ((b[off + 1] & 0xFF) +
((b[off + 0]) << 8)); (b[off] << 8));
} }
static short getShort(byte[] b, int off) { static short getShort(byte[] b, int off) {
return (short) (((b[off + 1] & 0xFF) << 0) + return (short) ((b[off + 1] & 0xFF) +
((b[off + 0]) << 8)); (b[off] << 8));
} }
static int getInt(byte[] b, int off) { static int getInt(byte[] b, int off) {
return ((b[off + 3] & 0xFF) << 0) + return ((b[off + 3] & 0xFF) ) +
((b[off + 2] & 0xFF) << 8) + ((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) + ((b[off + 1] & 0xFF) << 16) +
((b[off + 0]) << 24); ((b[off ] ) << 24);
} }
static float getFloat(byte[] b, int off) { static float getFloat(byte[] b, int off) {
int i = ((b[off + 3] & 0xFF) << 0) + return Float.intBitsToFloat(getInt(b, off));
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off + 0]) << 24);
return Float.intBitsToFloat(i);
} }
static long getLong(byte[] b, int off) { static long getLong(byte[] b, int off) {
return ((b[off + 7] & 0xFFL) << 0) + return ((b[off + 7] & 0xFFL) ) +
((b[off + 6] & 0xFFL) << 8) + ((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) + ((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) + ((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) + ((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) + ((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) + ((b[off + 1] & 0xFFL) << 48) +
(((long) b[off + 0]) << 56); (((long) b[off]) << 56);
} }
static double getDouble(byte[] b, int off) { static double getDouble(byte[] b, int off) {
long j = ((b[off + 7] & 0xFFL) << 0) + return Double.longBitsToDouble(getLong(b, off));
((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
(((long) b[off + 0]) << 56);
return Double.longBitsToDouble(j);
} }
/* /*
...@@ -98,50 +86,38 @@ class Bits { ...@@ -98,50 +86,38 @@ class Bits {
} }
static void putChar(byte[] b, int off, char val) { static void putChar(byte[] b, int off, char val) {
b[off + 1] = (byte) (val >>> 0); b[off + 1] = (byte) (val );
b[off + 0] = (byte) (val >>> 8); b[off ] = (byte) (val >>> 8);
} }
static void putShort(byte[] b, int off, short val) { static void putShort(byte[] b, int off, short val) {
b[off + 1] = (byte) (val >>> 0); b[off + 1] = (byte) (val );
b[off + 0] = (byte) (val >>> 8); b[off ] = (byte) (val >>> 8);
} }
static void putInt(byte[] b, int off, int val) { static void putInt(byte[] b, int off, int val) {
b[off + 3] = (byte) (val >>> 0); b[off + 3] = (byte) (val );
b[off + 2] = (byte) (val >>> 8); b[off + 2] = (byte) (val >>> 8);
b[off + 1] = (byte) (val >>> 16); b[off + 1] = (byte) (val >>> 16);
b[off + 0] = (byte) (val >>> 24); b[off ] = (byte) (val >>> 24);
} }
static void putFloat(byte[] b, int off, float val) { static void putFloat(byte[] b, int off, float val) {
int i = Float.floatToIntBits(val); putInt(b, off, Float.floatToIntBits(val));
b[off + 3] = (byte) (i >>> 0);
b[off + 2] = (byte) (i >>> 8);
b[off + 1] = (byte) (i >>> 16);
b[off + 0] = (byte) (i >>> 24);
} }
static void putLong(byte[] b, int off, long val) { static void putLong(byte[] b, int off, long val) {
b[off + 7] = (byte) (val >>> 0); b[off + 7] = (byte) (val );
b[off + 6] = (byte) (val >>> 8); b[off + 6] = (byte) (val >>> 8);
b[off + 5] = (byte) (val >>> 16); b[off + 5] = (byte) (val >>> 16);
b[off + 4] = (byte) (val >>> 24); b[off + 4] = (byte) (val >>> 24);
b[off + 3] = (byte) (val >>> 32); b[off + 3] = (byte) (val >>> 32);
b[off + 2] = (byte) (val >>> 40); b[off + 2] = (byte) (val >>> 40);
b[off + 1] = (byte) (val >>> 48); b[off + 1] = (byte) (val >>> 48);
b[off + 0] = (byte) (val >>> 56); b[off ] = (byte) (val >>> 56);
} }
static void putDouble(byte[] b, int off, double val) { static void putDouble(byte[] b, int off, double val) {
long j = Double.doubleToLongBits(val); putLong(b, off, Double.doubleToLongBits(val));
b[off + 7] = (byte) (j >>> 0);
b[off + 6] = (byte) (j >>> 8);
b[off + 5] = (byte) (j >>> 16);
b[off + 4] = (byte) (j >>> 24);
b[off + 3] = (byte) (j >>> 32);
b[off + 2] = (byte) (j >>> 40);
b[off + 1] = (byte) (j >>> 48);
b[off + 0] = (byte) (j >>> 56);
} }
} }
...@@ -28,14 +28,14 @@ package java.io; ...@@ -28,14 +28,14 @@ package java.io;
import java.io.IOException; import java.io.IOException;
/** /**
* A <tt>Closeable</tt> is a source or destination of data that can be closed. * A {@code Closeable} is a source or destination of data that can be closed.
* The close method is invoked to release resources that the object is * The close method is invoked to release resources that the object is
* holding (such as open files). * holding (such as open files).
* *
* @since 1.5 * @since 1.5
*/ */
public interface Closeable { public interface Closeable extends AutoCloseable {
/** /**
* Closes this stream and releases any system resources associated * Closes this stream and releases any system resources associated
...@@ -45,5 +45,4 @@ public interface Closeable { ...@@ -45,5 +45,4 @@ public interface Closeable {
* @throws IOException if an I/O error occurs * @throws IOException if an I/O error occurs
*/ */
public void close() throws IOException; public void close() throws IOException;
} }
...@@ -36,7 +36,7 @@ package java.io; ...@@ -36,7 +36,7 @@ package java.io;
* @see java.io.ObjectInputStream * @see java.io.ObjectInputStream
* @since JDK1.1 * @since JDK1.1
*/ */
public interface ObjectInput extends DataInput { public interface ObjectInput extends DataInput, AutoCloseable {
/** /**
* Read and return an object. The class that implements this interface * Read and return an object. The class that implements this interface
* defines where the object is "read" from. * defines where the object is "read" from.
......
...@@ -36,7 +36,7 @@ package java.io; ...@@ -36,7 +36,7 @@ package java.io;
* @see java.io.ObjectInputStream * @see java.io.ObjectInputStream
* @since JDK1.1 * @since JDK1.1
*/ */
public interface ObjectOutput extends DataOutput { public interface ObjectOutput extends DataOutput, AutoCloseable {
/** /**
* Write an object to the underlying storage or stream. The * Write an object to the underlying storage or stream. The
* class that implements this interface defines how the object is * class that implements this interface defines how the object is
......
...@@ -721,19 +721,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -721,19 +721,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@code codePoint} isn't a valid Unicode code point * {@code codePoint} isn't a valid Unicode code point
*/ */
public AbstractStringBuilder appendCodePoint(int codePoint) { public AbstractStringBuilder appendCodePoint(int codePoint) {
if (!Character.isValidCodePoint(codePoint)) { final int count = this.count;
throw new IllegalArgumentException();
} if (Character.isBmpCodePoint(codePoint)) {
int n = 1; ensureCapacityInternal(count + 1);
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { value[count] = (char) codePoint;
n++; this.count = count + 1;
} } else if (Character.isValidCodePoint(codePoint)) {
ensureCapacityInternal(count + n); ensureCapacityInternal(count + 2);
if (n == 1) {
value[count++] = (char) codePoint;
} else {
Character.toSurrogates(codePoint, value, count); Character.toSurrogates(codePoint, value, count);
count += n; this.count = count + 2;
} else {
throw new IllegalArgumentException();
} }
return this; return this;
} }
......
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute 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 java.lang;
/**
* A resource that must be closed when it is no longer needed.
*
* @author Josh Bloch
* @since 1.7
*/
public interface AutoCloseable {
/**
* Close this resource, relinquishing any underlying resources.
* This method is invoked automatically by the automatic resource
* management block construct.
*
* <p>Classes implementing this method are strongly encouraged to
* be declared to throw more specific exceptions (or no exception
* at all, if the close cannot fail).
*
* @throws Exception if this resource cannot be closed
*/
void close() throws Exception;
}
...@@ -38,7 +38,6 @@ import java.util.regex.Matcher; ...@@ -38,7 +38,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
/** /**
* The <code>String</code> class represents character strings. All * The <code>String</code> class represents character strings. All
* string literals in Java programs, such as <code>"abc"</code>, are * string literals in Java programs, such as <code>"abc"</code>, are
...@@ -99,6 +98,8 @@ import java.util.regex.PatternSyntaxException; ...@@ -99,6 +98,8 @@ import java.util.regex.PatternSyntaxException;
* *
* @author Lee Boynton * @author Lee Boynton
* @author Arthur van Hoff * @author Arthur van Hoff
* @author Martin Buchholz
* @author Ulf Zibis
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
* @see java.lang.StringBuffer * @see java.lang.StringBuffer
* @see java.lang.StringBuilder * @see java.lang.StringBuilder
...@@ -273,32 +274,32 @@ public final class String ...@@ -273,32 +274,32 @@ public final class String
throw new StringIndexOutOfBoundsException(offset + count); throw new StringIndexOutOfBoundsException(offset + count);
} }
final int end = offset + count;
// Pass 1: Compute precise size of char[] // Pass 1: Compute precise size of char[]
int n = 0; int n = count;
for (int i = offset; i < offset + count; i++) { for (int i = offset; i < end; i++) {
int c = codePoints[i]; int c = codePoints[i];
if (c >= Character.MIN_CODE_POINT && if (Character.isBmpCodePoint(c))
c < Character.MIN_SUPPLEMENTARY_CODE_POINT) continue;
n += 1; else if (Character.isValidCodePoint(c))
else if (Character.isSupplementaryCodePoint(c)) n++;
n += 2;
else throw new IllegalArgumentException(Integer.toString(c)); else throw new IllegalArgumentException(Integer.toString(c));
} }
// Pass 2: Allocate and fill in char[] // Pass 2: Allocate and fill in char[]
char[] v = new char[n]; final char[] v = new char[n];
for (int i = offset, j = 0; i < offset + count; i++) {
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i]; int c = codePoints[i];
if (c < Character.MIN_SUPPLEMENTARY_CODE_POINT) { if (Character.isBmpCodePoint(c))
v[j++] = (char) c; v[j] = (char) c;
} else { else
Character.toSurrogates(c, v, j); Character.toSurrogates(c, v, j++);
j += 2;
}
} }
this.value = v; this.value = v;
this.count = v.length; this.count = n;
this.offset = 0; this.offset = 0;
} }
...@@ -1573,9 +1574,6 @@ public final class String ...@@ -1573,9 +1574,6 @@ public final class String
* if the character does not occur. * if the character does not occur.
*/ */
public int indexOf(int ch, int fromIndex) { public int indexOf(int ch, int fromIndex) {
int max = offset + count;
char v[] = value;
if (fromIndex < 0) { if (fromIndex < 0) {
fromIndex = 0; fromIndex = 0;
} else if (fromIndex >= count) { } else if (fromIndex >= count) {
...@@ -1583,32 +1581,39 @@ public final class String ...@@ -1583,32 +1581,39 @@ public final class String
return -1; return -1;
} }
int i = offset + fromIndex;
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a // handle most cases here (ch is a BMP code point or a
// negative value (invalid code point)) // negative value (invalid code point))
for (; i < max ; i++) { final char[] value = this.value;
if (v[i] == ch) { final int offset = this.offset;
final int max = offset + count;
for (int i = offset + fromIndex; i < max ; i++) {
if (value[i] == ch) {
return i - offset; return i - offset;
} }
} }
return -1; return -1;
} else {
return indexOfSupplementary(ch, fromIndex);
} }
if (ch <= Character.MAX_CODE_POINT) {
// handle supplementary characters here
char[] surrogates = Character.toChars(ch);
for (; i < max; i++) {
if (v[i] == surrogates[0]) {
if (i + 1 == max) {
break;
} }
if (v[i+1] == surrogates[1]) {
/**
* Handles (rare) calls of indexOf with a supplementary character.
*/
private int indexOfSupplementary(int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[] value = this.value;
final int offset = this.offset;
final char hi = Character.highSurrogate(ch);
final char lo = Character.lowSurrogate(ch);
final int max = offset + count - 1;
for (int i = offset + fromIndex; i < max; i++) {
if (value[i] == hi && value[i+1] == lo) {
return i - offset; return i - offset;
} }
} }
} }
}
return -1; return -1;
} }
...@@ -1674,54 +1679,55 @@ public final class String ...@@ -1674,54 +1679,55 @@ public final class String
* if the character does not occur before that point. * if the character does not occur before that point.
*/ */
public int lastIndexOf(int ch, int fromIndex) { public int lastIndexOf(int ch, int fromIndex) {
int min = offset;
char v[] = value;
int i = offset + ((fromIndex >= count) ? count - 1 : fromIndex);
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a // handle most cases here (ch is a BMP code point or a
// negative value (invalid code point)) // negative value (invalid code point))
for (; i >= min ; i--) { final char[] value = this.value;
if (v[i] == ch) { final int offset = this.offset;
int i = offset + Math.min(fromIndex, count - 1);
for (; i >= offset ; i--) {
if (value[i] == ch) {
return i - offset; return i - offset;
} }
} }
return -1; return -1;
} else {
return lastIndexOfSupplementary(ch, fromIndex);
} }
int max = offset + count;
if (ch <= Character.MAX_CODE_POINT) {
// handle supplementary characters here
char[] surrogates = Character.toChars(ch);
for (; i >= min; i--) {
if (v[i] == surrogates[0]) {
if (i + 1 == max) {
break;
} }
if (v[i+1] == surrogates[1]) {
/**
* Handles (rare) calls of lastIndexOf with a supplementary character.
*/
private int lastIndexOfSupplementary(int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[] value = this.value;
final int offset = this.offset;
char hi = Character.highSurrogate(ch);
char lo = Character.lowSurrogate(ch);
int i = offset + Math.min(fromIndex, count - 2);
for (; i >= offset; i--) {
if (value[i] == hi && value[i+1] == lo) {
return i - offset; return i - offset;
} }
} }
} }
}
return -1; return -1;
} }
/** /**
* Returns the index within this string of the first occurrence of the * Returns the index within this string of the first occurrence of the
* specified substring. The integer returned is the smallest value * specified substring.
* <i>k</i> such that: *
* <p>The returned index is the smallest value <i>k</i> for which:
* <blockquote><pre> * <blockquote><pre>
* this.startsWith(str, <i>k</i>) * this.startsWith(str, <i>k</i>)
* </pre></blockquote> * </pre></blockquote>
* is <code>true</code>. * If no such value of <i>k</i> exists, then {@code -1} is returned.
* *
* @param str any string. * @param str the substring to search for.
* @return if the string argument occurs as a substring within this * @return the index of the first occurrence of the specified substring,
* object, then the index of the first character of the first * or {@code -1} if there is no such occurrence.
* such substring is returned; if it does not occur as a
* substring, <code>-1</code> is returned.
*/ */
public int indexOf(String str) { public int indexOf(String str) {
return indexOf(str, 0); return indexOf(str, 0);
...@@ -1729,17 +1735,19 @@ public final class String ...@@ -1729,17 +1735,19 @@ public final class String
/** /**
* Returns the index within this string of the first occurrence of the * Returns the index within this string of the first occurrence of the
* specified substring, starting at the specified index. The integer * specified substring, starting at the specified index.
* returned is the smallest value <tt>k</tt> for which: *
* <p>The returned index is the smallest value <i>k</i> for which:
* <blockquote><pre> * <blockquote><pre>
* k &gt;= Math.min(fromIndex, this.length()) && this.startsWith(str, k) * <i>k</i> &gt;= fromIndex && this.startsWith(str, <i>k</i>)
* </pre></blockquote> * </pre></blockquote>
* If no such value of <i>k</i> exists, then -1 is returned. * If no such value of <i>k</i> exists, then {@code -1} is returned.
* *
* @param str the substring for which to search. * @param str the substring to search for.
* @param fromIndex the index from which to start the search. * @param fromIndex the index from which to start the search.
* @return the index within this string of the first occurrence of the * @return the index of the first occurrence of the specified substring,
* specified substring, starting at the specified index. * starting at the specified index,
* or {@code -1} if there is no such occurrence.
*/ */
public int indexOf(String str, int fromIndex) { public int indexOf(String str, int fromIndex) {
return indexOf(value, offset, count, return indexOf(value, offset, count,
...@@ -1798,20 +1806,19 @@ public final class String ...@@ -1798,20 +1806,19 @@ public final class String
} }
/** /**
* Returns the index within this string of the rightmost occurrence * Returns the index within this string of the last occurrence of the
* of the specified substring. The rightmost empty string "" is * specified substring. The last occurrence of the empty string ""
* considered to occur at the index value <code>this.length()</code>. * is considered to occur at the index value {@code this.length()}.
* The returned index is the largest value <i>k</i> such that *
* <p>The returned index is the largest value <i>k</i> for which:
* <blockquote><pre> * <blockquote><pre>
* this.startsWith(str, k) * this.startsWith(str, <i>k</i>)
* </pre></blockquote> * </pre></blockquote>
* is true. * If no such value of <i>k</i> exists, then {@code -1} is returned.
* *
* @param str the substring to search for. * @param str the substring to search for.
* @return if the string argument occurs one or more times as a substring * @return the index of the last occurrence of the specified substring,
* within this object, then the index of the first character of * or {@code -1} if there is no such occurrence.
* the last such substring is returned. If it does not occur as
* a substring, <code>-1</code> is returned.
*/ */
public int lastIndexOf(String str) { public int lastIndexOf(String str) {
return lastIndexOf(str, count); return lastIndexOf(str, count);
...@@ -1820,16 +1827,18 @@ public final class String ...@@ -1820,16 +1827,18 @@ public final class String
/** /**
* Returns the index within this string of the last occurrence of the * Returns the index within this string of the last occurrence of the
* specified substring, searching backward starting at the specified index. * specified substring, searching backward starting at the specified index.
* The integer returned is the largest value <i>k</i> such that: *
* <p>The returned index is the largest value <i>k</i> for which:
* <blockquote><pre> * <blockquote><pre>
* k &lt;= Math.min(fromIndex, this.length()) && this.startsWith(str, k) * <i>k</i> &lt;= fromIndex && this.startsWith(str, <i>k</i>)
* </pre></blockquote> * </pre></blockquote>
* If no such value of <i>k</i> exists, then -1 is returned. * If no such value of <i>k</i> exists, then {@code -1} is returned.
* *
* @param str the substring to search for. * @param str the substring to search for.
* @param fromIndex the index to start the search from. * @param fromIndex the index to start the search from.
* @return the index within this string of the last occurrence of the * @return the index of the last occurrence of the specified substring,
* specified substring. * searching backward from the specified index,
* or {@code -1} if there is no such occurrence.
*/ */
public int lastIndexOf(String str, int fromIndex) { public int lastIndexOf(String str, int fromIndex) {
return lastIndexOf(value, offset, count, return lastIndexOf(value, offset, count,
......
...@@ -69,7 +69,7 @@ public final class System { ...@@ -69,7 +69,7 @@ public final class System {
* corresponds to keyboard input or another input source specified by * corresponds to keyboard input or another input source specified by
* the host environment or user. * the host environment or user.
*/ */
public final static InputStream in = nullInputStream(); public final static InputStream in = null;
/** /**
* The "standard" output stream. This stream is already * The "standard" output stream. This stream is already
...@@ -96,7 +96,7 @@ public final class System { ...@@ -96,7 +96,7 @@ public final class System {
* @see java.io.PrintStream#println(java.lang.Object) * @see java.io.PrintStream#println(java.lang.Object)
* @see java.io.PrintStream#println(java.lang.String) * @see java.io.PrintStream#println(java.lang.String)
*/ */
public final static PrintStream out = nullPrintStream(); public final static PrintStream out = null;
/** /**
* The "standard" error output stream. This stream is already * The "standard" error output stream. This stream is already
...@@ -110,7 +110,7 @@ public final class System { ...@@ -110,7 +110,7 @@ public final class System {
* variable <code>out</code>, has been redirected to a file or other * variable <code>out</code>, has been redirected to a file or other
* destination that is typically not continuously monitored. * destination that is typically not continuously monitored.
*/ */
public final static PrintStream err = nullPrintStream(); public final static PrintStream err = null;
/* The security manager for the system. /* The security manager for the system.
*/ */
...@@ -1092,26 +1092,6 @@ public final class System { ...@@ -1092,26 +1092,6 @@ public final class System {
*/ */
public static native String mapLibraryName(String libname); public static native String mapLibraryName(String libname);
/**
* The following two methods exist because in, out, and err must be
* initialized to null. The compiler, however, cannot be permitted to
* inline access to them, since they are later set to more sensible values
* by initializeSystemClass().
*/
private static InputStream nullInputStream() throws NullPointerException {
if (currentTimeMillis() > 0) {
return null;
}
throw new NullPointerException();
}
private static PrintStream nullPrintStream() throws NullPointerException {
if (currentTimeMillis() > 0) {
return null;
}
throw new NullPointerException();
}
/** /**
* Initialize the system class. Called after thread initialization. * Initialize the system class. Called after thread initialization.
*/ */
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package java.lang; package java.lang;
import java.io.*; import java.io.*;
import java.util.*;
/** /**
* The <code>Throwable</code> class is the superclass of all errors and * The <code>Throwable</code> class is the superclass of all errors and
...@@ -102,7 +103,7 @@ import java.io.*; ...@@ -102,7 +103,7 @@ import java.io.*;
* lowLevelOp(); * lowLevelOp();
* } catch (LowLevelException le) { * } catch (LowLevelException le) {
* throw (HighLevelException) * throw (HighLevelException)
new HighLevelException().initCause(le); // Legacy constructor * new HighLevelException().initCause(le); // Legacy constructor
* } * }
* </pre> * </pre>
* *
...@@ -192,6 +193,24 @@ public class Throwable implements Serializable { ...@@ -192,6 +193,24 @@ public class Throwable implements Serializable {
* nulled out when fillInStackTrace is called. * nulled out when fillInStackTrace is called.
*/ */
/**
* The list of suppressed exceptions, as returned by
* {@link #getSuppressedExceptions()}.
*
* @serial
* @since 1.7
*/
private List<Throwable> suppressedExceptions = Collections.emptyList();
/** Message for trying to suppress a null exception. */
private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
/** Caption for labeling causative exception stack traces */
private static final String CAUSE_CAPTION = "Caused by: ";
/** Caption for labeling suppressed exception stack traces */
private static final String SUPPRESSED_CAPTION = "Suppressed: ";
/** /**
* Constructs a new throwable with <code>null</code> as its detail message. * Constructs a new throwable with <code>null</code> as its detail message.
* The cause is not initialized, and may subsequently be initialized by a * The cause is not initialized, and may subsequently be initialized by a
...@@ -469,6 +488,52 @@ public class Throwable implements Serializable { ...@@ -469,6 +488,52 @@ public class Throwable implements Serializable {
* class LowLevelException extends Exception { * class LowLevelException extends Exception {
* } * }
* </pre> * </pre>
* As of release 7, the platform supports the notion of
* <i>suppressed exceptions</i> (in conjunction with automatic
* resource management blocks). Any exceptions that were
* suppressed in order to deliver an exception are printed out
* beneath the stack trace. The format of this information
* depends on the implementation, but the following example may be
* regarded as typical:
*
* <pre>
* Exception in thread "main" java.lang.Exception: Something happened
* at Foo.bar(Foo.java:10)
* at Foo.main(Foo.java:5)
* Suppressed: Resource$CloseFailException: Resource ID = 0
* at Resource.close(Resource.java:26)
* at Foo.bar(Foo.java:9)
* ... 1 more
* </pre>
* Note that the "... n more" notation is used on suppressed exceptions
* just at it is used on causes. Unlike causes, suppressed exceptions are
* indented beyond their "containing exceptions."
*
* <p>An exception can have both a cause and one or more suppressed
* exceptions:
* <pre>
* Exception in thread "main" java.lang.Exception: Main block
* at Foo3.main(Foo3.java:7)
* Suppressed: Resource$CloseFailException: Resource ID = 2
* at Resource.close(Resource.java:26)
* at Foo3.main(Foo3.java:5)
* Suppressed: Resource$CloseFailException: Resource ID = 1
* at Resource.close(Resource.java:26)
* at Foo3.main(Foo3.java:5)
* Caused by: java.lang.Exception: I did it
* at Foo3.main(Foo3.java:8)
* </pre>
* Likewise, a suppressed exception can have a cause:
* <pre>
* Exception in thread "main" java.lang.Exception: Main block
* at Foo4.main(Foo4.java:6)
* Suppressed: Resource2$CloseFailException: Resource ID = 1
* at Resource2.close(Resource2.java:20)
* at Foo4.main(Foo4.java:5)
* Caused by: java.lang.Exception: Rats, you caught me
* at Resource2$CloseFailException.<init>(Resource2.java:45)
* ... 2 more
* </pre>
*/ */
public void printStackTrace() { public void printStackTrace() {
printStackTrace(System.err); printStackTrace(System.err);
...@@ -480,44 +545,71 @@ public class Throwable implements Serializable { ...@@ -480,44 +545,71 @@ public class Throwable implements Serializable {
* @param s <code>PrintStream</code> to use for output * @param s <code>PrintStream</code> to use for output
*/ */
public void printStackTrace(PrintStream s) { public void printStackTrace(PrintStream s) {
synchronized (s) { printStackTrace(new WrappedPrintStream(s));
}
private void printStackTrace(PrintStreamOrWriter s) {
Set<Throwable> dejaVu = new HashSet<Throwable>();
dejaVu.add(this);
synchronized (s.lock()) {
// Print our stack trace
s.println(this); s.println(this);
StackTraceElement[] trace = getOurStackTrace(); StackTraceElement[] trace = getOurStackTrace();
for (int i=0; i < trace.length; i++) for (StackTraceElement traceElement : trace)
s.println("\tat " + trace[i]); s.println("\tat " + traceElement);
// Print suppressed exceptions, if any
for (Throwable se : suppressedExceptions)
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
// Print cause, if any
Throwable ourCause = getCause(); Throwable ourCause = getCause();
if (ourCause != null) if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace); ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
} }
} }
/** /**
* Print our stack trace as a cause for the specified stack trace. * Print our stack trace as an enclosed exception for the specified
* stack trace.
*/ */
private void printStackTraceAsCause(PrintStream s, private void printEnclosedStackTrace(PrintStreamOrWriter s,
StackTraceElement[] causedTrace) StackTraceElement[] enclosingTrace,
{ String caption,
// assert Thread.holdsLock(s); String prefix,
Set<Throwable> dejaVu) {
// Compute number of frames in common between this and caused assert Thread.holdsLock(s.lock());
if (dejaVu.contains(this)) {
s.println("\t[CIRCULAR REFERENCE:" + this + "]");
} else {
dejaVu.add(this);
// Compute number of frames in common between this and enclosing trace
StackTraceElement[] trace = getOurStackTrace(); StackTraceElement[] trace = getOurStackTrace();
int m = trace.length-1, n = causedTrace.length-1; int m = trace.length - 1;
while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { int n = enclosingTrace.length - 1;
while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
m--; n--; m--; n--;
} }
int framesInCommon = trace.length - 1 - m; int framesInCommon = trace.length - 1 - m;
s.println("Caused by: " + this); // Print our stack trace
for (int i=0; i <= m; i++) s.println(prefix + caption + this);
s.println("\tat " + trace[i]); for (int i = 0; i <= m; i++)
s.println(prefix + "\tat " + trace[i]);
if (framesInCommon != 0) if (framesInCommon != 0)
s.println("\t... " + framesInCommon + " more"); s.println(prefix + "\t... " + framesInCommon + " more");
// Recurse if we have a cause // Print suppressed exceptions, if any
for (Throwable se : suppressedExceptions)
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
prefix +"\t", dejaVu);
// Print cause, if any
Throwable ourCause = getCause(); Throwable ourCause = getCause();
if (ourCause != null) if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace); ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
}
} }
/** /**
...@@ -528,44 +620,51 @@ public class Throwable implements Serializable { ...@@ -528,44 +620,51 @@ public class Throwable implements Serializable {
* @since JDK1.1 * @since JDK1.1
*/ */
public void printStackTrace(PrintWriter s) { public void printStackTrace(PrintWriter s) {
synchronized (s) { printStackTrace(new WrappedPrintWriter(s));
s.println(this);
StackTraceElement[] trace = getOurStackTrace();
for (int i=0; i < trace.length; i++)
s.println("\tat " + trace[i]);
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace);
}
} }
/** /**
* Print our stack trace as a cause for the specified stack trace. * Wrapper class for PrintStream and PrintWriter to enable a single
* implementation of printStackTrace.
*/ */
private void printStackTraceAsCause(PrintWriter s, private abstract static class PrintStreamOrWriter {
StackTraceElement[] causedTrace) /** Returns the object to be locked when using this StreamOrWriter */
{ abstract Object lock();
// assert Thread.holdsLock(s);
// Compute number of frames in common between this and caused /** Prints the specified string as a line on this StreamOrWriter */
StackTraceElement[] trace = getOurStackTrace(); abstract void println(Object o);
int m = trace.length-1, n = causedTrace.length-1;
while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
m--; n--;
} }
int framesInCommon = trace.length - 1 - m;
s.println("Caused by: " + this); private static class WrappedPrintStream extends PrintStreamOrWriter {
for (int i=0; i <= m; i++) private final PrintStream printStream;
s.println("\tat " + trace[i]);
if (framesInCommon != 0)
s.println("\t... " + framesInCommon + " more");
// Recurse if we have a cause WrappedPrintStream(PrintStream printStream) {
Throwable ourCause = getCause(); this.printStream = printStream;
if (ourCause != null) }
ourCause.printStackTraceAsCause(s, trace);
Object lock() {
return printStream;
}
void println(Object o) {
printStream.println(o);
}
}
private static class WrappedPrintWriter extends PrintStreamOrWriter {
private final PrintWriter printWriter;
WrappedPrintWriter(PrintWriter printWriter) {
this.printWriter = printWriter;
}
Object lock() {
return printWriter;
}
void println(Object o) {
printWriter.println(o);
}
} }
/** /**
...@@ -667,10 +766,60 @@ public class Throwable implements Serializable { ...@@ -667,10 +766,60 @@ public class Throwable implements Serializable {
*/ */
native StackTraceElement getStackTraceElement(int index); native StackTraceElement getStackTraceElement(int index);
private synchronized void writeObject(java.io.ObjectOutputStream s) private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject(); // read in all fields
List<Throwable> suppressed = Collections.emptyList();
if (suppressedExceptions != null &&
!suppressedExceptions.isEmpty()) { // Copy Throwables to new list
suppressed = new ArrayList<Throwable>();
for(Throwable t : suppressedExceptions) {
if (t == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
suppressed.add(t);
}
}
suppressedExceptions = suppressed;
}
private synchronized void writeObject(ObjectOutputStream s)
throws IOException throws IOException
{ {
getOurStackTrace(); // Ensure that stackTrace field is initialized. getOurStackTrace(); // Ensure that stackTrace field is initialized.
s.defaultWriteObject(); s.defaultWriteObject();
} }
/**
* Adds the specified exception to the list of exceptions that
* were suppressed, typically by the automatic resource management
* statement, in order to deliver this exception.
*
* @param exception the exception to be added to the list of
* suppressed exceptions
* @throws NullPointerException if {@code exception} is null
* @since 1.7
*/
public synchronized void addSuppressedException(Throwable exception) {
if (exception == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
if (suppressedExceptions.size() == 0)
suppressedExceptions = new ArrayList<Throwable>();
suppressedExceptions.add(exception);
}
private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
/**
* Returns an array containing all of the exceptions that were
* suppressed, typically by the automatic resource management
* statement, in order to deliver this exception.
*
* @return an array containing all of the exceptions that were
* suppressed to deliver this exception.
* @since 1.7
*/
public Throwable[] getSuppressedExceptions() {
return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
}
} }
...@@ -427,8 +427,9 @@ class Inet6Address extends InetAddress { ...@@ -427,8 +427,9 @@ class Inet6Address extends InetAddress {
try { try {
scope_id = deriveNumericScope (scope_ifname); scope_id = deriveNumericScope (scope_ifname);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
// should not happen // typically should not happen, but it may be that
assert false; // the machine being used for deserialization has
// the same interface name but without IPv6 configured.
} }
} }
} catch (SocketException e) {} } catch (SocketException e) {}
......
...@@ -41,25 +41,19 @@ class Bits { // package-private ...@@ -41,25 +41,19 @@ class Bits { // package-private
// -- Swapping -- // -- Swapping --
static short swap(short x) { static short swap(short x) {
return (short)((x << 8) | return Short.reverseBytes(x);
((char)x >>> 8));
} }
static char swap(char x) { static char swap(char x) {
return (char)((x << 8) | return Character.reverseBytes(x);
(x >>> 8));
} }
static int swap(int x) { static int swap(int x) {
return ((x << 24) | return Integer.reverseBytes(x);
((x & 0x0000ff00) << 8) |
((x & 0x00ff0000) >>> 8) |
(x >>> 24));
} }
static long swap(long x) { static long swap(long x) {
return (((long)swap((int)x) << 32) | return Long.reverseBytes(x);
((long)swap((int)(x >>> 32)) & 0xffffffffL));
} }
...@@ -71,52 +65,52 @@ class Bits { // package-private ...@@ -71,52 +65,52 @@ class Bits { // package-private
static char getCharL(ByteBuffer bb, int bi) { static char getCharL(ByteBuffer bb, int bi) {
return makeChar(bb._get(bi + 1), return makeChar(bb._get(bi + 1),
bb._get(bi + 0)); bb._get(bi ));
} }
static char getCharL(long a) { static char getCharL(long a) {
return makeChar(_get(a + 1), return makeChar(_get(a + 1),
_get(a + 0)); _get(a ));
} }
static char getCharB(ByteBuffer bb, int bi) { static char getCharB(ByteBuffer bb, int bi) {
return makeChar(bb._get(bi + 0), return makeChar(bb._get(bi ),
bb._get(bi + 1)); bb._get(bi + 1));
} }
static char getCharB(long a) { static char getCharB(long a) {
return makeChar(_get(a + 0), return makeChar(_get(a ),
_get(a + 1)); _get(a + 1));
} }
static char getChar(ByteBuffer bb, int bi, boolean bigEndian) { static char getChar(ByteBuffer bb, int bi, boolean bigEndian) {
return (bigEndian ? getCharB(bb, bi) : getCharL(bb, bi)); return bigEndian ? getCharB(bb, bi) : getCharL(bb, bi);
} }
static char getChar(long a, boolean bigEndian) { static char getChar(long a, boolean bigEndian) {
return (bigEndian ? getCharB(a) : getCharL(a)); return bigEndian ? getCharB(a) : getCharL(a);
} }
private static byte char1(char x) { return (byte)(x >> 8); } private static byte char1(char x) { return (byte)(x >> 8); }
private static byte char0(char x) { return (byte)(x >> 0); } private static byte char0(char x) { return (byte)(x ); }
static void putCharL(ByteBuffer bb, int bi, char x) { static void putCharL(ByteBuffer bb, int bi, char x) {
bb._put(bi + 0, char0(x)); bb._put(bi , char0(x));
bb._put(bi + 1, char1(x)); bb._put(bi + 1, char1(x));
} }
static void putCharL(long a, char x) { static void putCharL(long a, char x) {
_put(a + 0, char0(x)); _put(a , char0(x));
_put(a + 1, char1(x)); _put(a + 1, char1(x));
} }
static void putCharB(ByteBuffer bb, int bi, char x) { static void putCharB(ByteBuffer bb, int bi, char x) {
bb._put(bi + 0, char1(x)); bb._put(bi , char1(x));
bb._put(bi + 1, char0(x)); bb._put(bi + 1, char0(x));
} }
static void putCharB(long a, char x) { static void putCharB(long a, char x) {
_put(a + 0, char1(x)); _put(a , char1(x));
_put(a + 1, char0(x)); _put(a + 1, char0(x));
} }
...@@ -143,52 +137,52 @@ class Bits { // package-private ...@@ -143,52 +137,52 @@ class Bits { // package-private
static short getShortL(ByteBuffer bb, int bi) { static short getShortL(ByteBuffer bb, int bi) {
return makeShort(bb._get(bi + 1), return makeShort(bb._get(bi + 1),
bb._get(bi + 0)); bb._get(bi ));
} }
static short getShortL(long a) { static short getShortL(long a) {
return makeShort(_get(a + 1), return makeShort(_get(a + 1),
_get(a)); _get(a ));
} }
static short getShortB(ByteBuffer bb, int bi) { static short getShortB(ByteBuffer bb, int bi) {
return makeShort(bb._get(bi + 0), return makeShort(bb._get(bi ),
bb._get(bi + 1)); bb._get(bi + 1));
} }
static short getShortB(long a) { static short getShortB(long a) {
return makeShort(_get(a), return makeShort(_get(a ),
_get(a + 1)); _get(a + 1));
} }
static short getShort(ByteBuffer bb, int bi, boolean bigEndian) { static short getShort(ByteBuffer bb, int bi, boolean bigEndian) {
return (bigEndian ? getShortB(bb, bi) : getShortL(bb, bi)); return bigEndian ? getShortB(bb, bi) : getShortL(bb, bi);
} }
static short getShort(long a, boolean bigEndian) { static short getShort(long a, boolean bigEndian) {
return (bigEndian ? getShortB(a) : getShortL(a)); return bigEndian ? getShortB(a) : getShortL(a);
} }
private static byte short1(short x) { return (byte)(x >> 8); } private static byte short1(short x) { return (byte)(x >> 8); }
private static byte short0(short x) { return (byte)(x >> 0); } private static byte short0(short x) { return (byte)(x ); }
static void putShortL(ByteBuffer bb, int bi, short x) { static void putShortL(ByteBuffer bb, int bi, short x) {
bb._put(bi + 0, short0(x)); bb._put(bi , short0(x));
bb._put(bi + 1, short1(x)); bb._put(bi + 1, short1(x));
} }
static void putShortL(long a, short x) { static void putShortL(long a, short x) {
_put(a, short0(x)); _put(a , short0(x));
_put(a + 1, short1(x)); _put(a + 1, short1(x));
} }
static void putShortB(ByteBuffer bb, int bi, short x) { static void putShortB(ByteBuffer bb, int bi, short x) {
bb._put(bi + 0, short1(x)); bb._put(bi , short1(x));
bb._put(bi + 1, short0(x)); bb._put(bi + 1, short0(x));
} }
static void putShortB(long a, short x) { static void putShortB(long a, short x) {
_put(a, short1(x)); _put(a , short1(x));
_put(a + 1, short0(x)); _put(a + 1, short0(x));
} }
...@@ -210,76 +204,76 @@ class Bits { // package-private ...@@ -210,76 +204,76 @@ class Bits { // package-private
// -- get/put int -- // -- get/put int --
static private int makeInt(byte b3, byte b2, byte b1, byte b0) { static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
return (((b3 & 0xff) << 24) | return (((b3 ) << 24) |
((b2 & 0xff) << 16) | ((b2 & 0xff) << 16) |
((b1 & 0xff) << 8) | ((b1 & 0xff) << 8) |
((b0 & 0xff) << 0)); ((b0 & 0xff) ));
} }
static int getIntL(ByteBuffer bb, int bi) { static int getIntL(ByteBuffer bb, int bi) {
return makeInt(bb._get(bi + 3), return makeInt(bb._get(bi + 3),
bb._get(bi + 2), bb._get(bi + 2),
bb._get(bi + 1), bb._get(bi + 1),
bb._get(bi + 0)); bb._get(bi ));
} }
static int getIntL(long a) { static int getIntL(long a) {
return makeInt(_get(a + 3), return makeInt(_get(a + 3),
_get(a + 2), _get(a + 2),
_get(a + 1), _get(a + 1),
_get(a + 0)); _get(a ));
} }
static int getIntB(ByteBuffer bb, int bi) { static int getIntB(ByteBuffer bb, int bi) {
return makeInt(bb._get(bi + 0), return makeInt(bb._get(bi ),
bb._get(bi + 1), bb._get(bi + 1),
bb._get(bi + 2), bb._get(bi + 2),
bb._get(bi + 3)); bb._get(bi + 3));
} }
static int getIntB(long a) { static int getIntB(long a) {
return makeInt(_get(a + 0), return makeInt(_get(a ),
_get(a + 1), _get(a + 1),
_get(a + 2), _get(a + 2),
_get(a + 3)); _get(a + 3));
} }
static int getInt(ByteBuffer bb, int bi, boolean bigEndian) { static int getInt(ByteBuffer bb, int bi, boolean bigEndian) {
return (bigEndian ? getIntB(bb, bi) : getIntL(bb, bi)); return bigEndian ? getIntB(bb, bi) : getIntL(bb, bi) ;
} }
static int getInt(long a, boolean bigEndian) { static int getInt(long a, boolean bigEndian) {
return (bigEndian ? getIntB(a) : getIntL(a)); return bigEndian ? getIntB(a) : getIntL(a) ;
} }
private static byte int3(int x) { return (byte)(x >> 24); } private static byte int3(int x) { return (byte)(x >> 24); }
private static byte int2(int x) { return (byte)(x >> 16); } private static byte int2(int x) { return (byte)(x >> 16); }
private static byte int1(int x) { return (byte)(x >> 8); } private static byte int1(int x) { return (byte)(x >> 8); }
private static byte int0(int x) { return (byte)(x >> 0); } private static byte int0(int x) { return (byte)(x ); }
static void putIntL(ByteBuffer bb, int bi, int x) { static void putIntL(ByteBuffer bb, int bi, int x) {
bb._put(bi + 3, int3(x)); bb._put(bi + 3, int3(x));
bb._put(bi + 2, int2(x)); bb._put(bi + 2, int2(x));
bb._put(bi + 1, int1(x)); bb._put(bi + 1, int1(x));
bb._put(bi + 0, int0(x)); bb._put(bi , int0(x));
} }
static void putIntL(long a, int x) { static void putIntL(long a, int x) {
_put(a + 3, int3(x)); _put(a + 3, int3(x));
_put(a + 2, int2(x)); _put(a + 2, int2(x));
_put(a + 1, int1(x)); _put(a + 1, int1(x));
_put(a + 0, int0(x)); _put(a , int0(x));
} }
static void putIntB(ByteBuffer bb, int bi, int x) { static void putIntB(ByteBuffer bb, int bi, int x) {
bb._put(bi + 0, int3(x)); bb._put(bi , int3(x));
bb._put(bi + 1, int2(x)); bb._put(bi + 1, int2(x));
bb._put(bi + 2, int1(x)); bb._put(bi + 2, int1(x));
bb._put(bi + 3, int0(x)); bb._put(bi + 3, int0(x));
} }
static void putIntB(long a, int x) { static void putIntB(long a, int x) {
_put(a + 0, int3(x)); _put(a , int3(x));
_put(a + 1, int2(x)); _put(a + 1, int2(x));
_put(a + 2, int1(x)); _put(a + 2, int1(x));
_put(a + 3, int0(x)); _put(a + 3, int0(x));
...@@ -305,14 +299,14 @@ class Bits { // package-private ...@@ -305,14 +299,14 @@ class Bits { // package-private
static private long makeLong(byte b7, byte b6, byte b5, byte b4, static private long makeLong(byte b7, byte b6, byte b5, byte b4,
byte b3, byte b2, byte b1, byte b0) byte b3, byte b2, byte b1, byte b0)
{ {
return ((((long)b7 & 0xff) << 56) | return ((((long)b7 ) << 56) |
(((long)b6 & 0xff) << 48) | (((long)b6 & 0xff) << 48) |
(((long)b5 & 0xff) << 40) | (((long)b5 & 0xff) << 40) |
(((long)b4 & 0xff) << 32) | (((long)b4 & 0xff) << 32) |
(((long)b3 & 0xff) << 24) | (((long)b3 & 0xff) << 24) |
(((long)b2 & 0xff) << 16) | (((long)b2 & 0xff) << 16) |
(((long)b1 & 0xff) << 8) | (((long)b1 & 0xff) << 8) |
(((long)b0 & 0xff) << 0)); (((long)b0 & 0xff) ));
} }
static long getLongL(ByteBuffer bb, int bi) { static long getLongL(ByteBuffer bb, int bi) {
...@@ -323,7 +317,7 @@ class Bits { // package-private ...@@ -323,7 +317,7 @@ class Bits { // package-private
bb._get(bi + 3), bb._get(bi + 3),
bb._get(bi + 2), bb._get(bi + 2),
bb._get(bi + 1), bb._get(bi + 1),
bb._get(bi + 0)); bb._get(bi ));
} }
static long getLongL(long a) { static long getLongL(long a) {
...@@ -334,11 +328,11 @@ class Bits { // package-private ...@@ -334,11 +328,11 @@ class Bits { // package-private
_get(a + 3), _get(a + 3),
_get(a + 2), _get(a + 2),
_get(a + 1), _get(a + 1),
_get(a + 0)); _get(a ));
} }
static long getLongB(ByteBuffer bb, int bi) { static long getLongB(ByteBuffer bb, int bi) {
return makeLong(bb._get(bi + 0), return makeLong(bb._get(bi ),
bb._get(bi + 1), bb._get(bi + 1),
bb._get(bi + 2), bb._get(bi + 2),
bb._get(bi + 3), bb._get(bi + 3),
...@@ -349,7 +343,7 @@ class Bits { // package-private ...@@ -349,7 +343,7 @@ class Bits { // package-private
} }
static long getLongB(long a) { static long getLongB(long a) {
return makeLong(_get(a + 0), return makeLong(_get(a ),
_get(a + 1), _get(a + 1),
_get(a + 2), _get(a + 2),
_get(a + 3), _get(a + 3),
...@@ -360,11 +354,11 @@ class Bits { // package-private ...@@ -360,11 +354,11 @@ class Bits { // package-private
} }
static long getLong(ByteBuffer bb, int bi, boolean bigEndian) { static long getLong(ByteBuffer bb, int bi, boolean bigEndian) {
return (bigEndian ? getLongB(bb, bi) : getLongL(bb, bi)); return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi);
} }
static long getLong(long a, boolean bigEndian) { static long getLong(long a, boolean bigEndian) {
return (bigEndian ? getLongB(a) : getLongL(a)); return bigEndian ? getLongB(a) : getLongL(a);
} }
private static byte long7(long x) { return (byte)(x >> 56); } private static byte long7(long x) { return (byte)(x >> 56); }
...@@ -374,7 +368,7 @@ class Bits { // package-private ...@@ -374,7 +368,7 @@ class Bits { // package-private
private static byte long3(long x) { return (byte)(x >> 24); } private static byte long3(long x) { return (byte)(x >> 24); }
private static byte long2(long x) { return (byte)(x >> 16); } private static byte long2(long x) { return (byte)(x >> 16); }
private static byte long1(long x) { return (byte)(x >> 8); } private static byte long1(long x) { return (byte)(x >> 8); }
private static byte long0(long x) { return (byte)(x >> 0); } private static byte long0(long x) { return (byte)(x ); }
static void putLongL(ByteBuffer bb, int bi, long x) { static void putLongL(ByteBuffer bb, int bi, long x) {
bb._put(bi + 7, long7(x)); bb._put(bi + 7, long7(x));
...@@ -384,7 +378,7 @@ class Bits { // package-private ...@@ -384,7 +378,7 @@ class Bits { // package-private
bb._put(bi + 3, long3(x)); bb._put(bi + 3, long3(x));
bb._put(bi + 2, long2(x)); bb._put(bi + 2, long2(x));
bb._put(bi + 1, long1(x)); bb._put(bi + 1, long1(x));
bb._put(bi + 0, long0(x)); bb._put(bi , long0(x));
} }
static void putLongL(long a, long x) { static void putLongL(long a, long x) {
...@@ -395,11 +389,11 @@ class Bits { // package-private ...@@ -395,11 +389,11 @@ class Bits { // package-private
_put(a + 3, long3(x)); _put(a + 3, long3(x));
_put(a + 2, long2(x)); _put(a + 2, long2(x));
_put(a + 1, long1(x)); _put(a + 1, long1(x));
_put(a + 0, long0(x)); _put(a , long0(x));
} }
static void putLongB(ByteBuffer bb, int bi, long x) { static void putLongB(ByteBuffer bb, int bi, long x) {
bb._put(bi + 0, long7(x)); bb._put(bi , long7(x));
bb._put(bi + 1, long6(x)); bb._put(bi + 1, long6(x));
bb._put(bi + 2, long5(x)); bb._put(bi + 2, long5(x));
bb._put(bi + 3, long4(x)); bb._put(bi + 3, long4(x));
...@@ -410,7 +404,7 @@ class Bits { // package-private ...@@ -410,7 +404,7 @@ class Bits { // package-private
} }
static void putLongB(long a, long x) { static void putLongB(long a, long x) {
_put(a + 0, long7(x)); _put(a , long7(x));
_put(a + 1, long6(x)); _put(a + 1, long6(x));
_put(a + 2, long5(x)); _put(a + 2, long5(x));
_put(a + 3, long4(x)); _put(a + 3, long4(x));
...@@ -454,11 +448,11 @@ class Bits { // package-private ...@@ -454,11 +448,11 @@ class Bits { // package-private
} }
static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) { static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) {
return (bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi)); return bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi);
} }
static float getFloat(long a, boolean bigEndian) { static float getFloat(long a, boolean bigEndian) {
return (bigEndian ? getFloatB(a) : getFloatL(a)); return bigEndian ? getFloatB(a) : getFloatL(a);
} }
static void putFloatL(ByteBuffer bb, int bi, float x) { static void putFloatL(ByteBuffer bb, int bi, float x) {
...@@ -511,11 +505,11 @@ class Bits { // package-private ...@@ -511,11 +505,11 @@ class Bits { // package-private
} }
static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) { static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) {
return (bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi)); return bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi);
} }
static double getDouble(long a, boolean bigEndian) { static double getDouble(long a, boolean bigEndian) {
return (bigEndian ? getDoubleB(a) : getDoubleL(a)); return bigEndian ? getDoubleB(a) : getDoubleL(a);
} }
static void putDoubleL(ByteBuffer bb, int bi, double x) { static void putDoubleL(ByteBuffer bb, int bi, double x) {
......
...@@ -116,7 +116,7 @@ import java.io.IOException; ...@@ -116,7 +116,7 @@ import java.io.IOException;
* @since 1.4 * @since 1.4
*/ */
public abstract class FileLock { public abstract class FileLock implements AutoCloseable {
private final Channel channel; private final Channel channel;
private final long position; private final long position;
...@@ -298,6 +298,17 @@ public abstract class FileLock { ...@@ -298,6 +298,17 @@ public abstract class FileLock {
*/ */
public abstract void release() throws IOException; public abstract void release() throws IOException;
/**
* This method invokes the {@link #release} method. It was added
* to the class so that it could be used in conjunction with the
* automatic resource management block construct.
*
* @since 1.7
*/
public final void close() throws IOException {
release();
}
/** /**
* Returns a string describing the range, type, and validity of this lock. * Returns a string describing the range, type, and validity of this lock.
* *
......
...@@ -343,7 +343,7 @@ import sun.misc.LRUCache; ...@@ -343,7 +343,7 @@ import sun.misc.LRUCache;
* *
* @since 1.5 * @since 1.5
*/ */
public final class Scanner implements Iterator<String> { public final class Scanner implements Iterator<String>, Closeable {
// Internal buffer used to hold input // Internal buffer used to hold input
private CharBuffer buf; private CharBuffer buf;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package javax.imageio.stream; package javax.imageio.stream;
import java.io.Closeable;
import java.io.DataInput; import java.io.DataInput;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteOrder; import java.nio.ByteOrder;
...@@ -42,7 +43,7 @@ import java.nio.ByteOrder; ...@@ -42,7 +43,7 @@ import java.nio.ByteOrder;
* @see MemoryCacheImageInputStream * @see MemoryCacheImageInputStream
* *
*/ */
public interface ImageInputStream extends DataInput { public interface ImageInputStream extends DataInput, Closeable {
/** /**
* Sets the desired byte order for future reads of data values * Sets the desired byte order for future reads of data values
......
...@@ -107,7 +107,7 @@ import java.util.List; ...@@ -107,7 +107,7 @@ import java.util.List;
* @author Florian Bomers * @author Florian Bomers
*/ */
public interface MidiDevice { public interface MidiDevice extends AutoCloseable {
/** /**
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册