diff --git a/.hgignore b/.hgignore index ca1b0b21ee28363f9db52bbf650c3bbf1dba9d8b..be55e3a7c83827635d49ec818d2a03774c021752 100644 --- a/.hgignore +++ b/.hgignore @@ -1,3 +1,6 @@ ^build/ ^dist/ ^nbproject/private/ +^make/netbeans/.*/nbproject/private/ +^make/netbeans/.*/build/ +^make/netbeans/.*/dist/ diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk index 4fb524a7dd47506c21b8211b029578f49226c9e2..f3ba8254868d816ac899db2d23f86db5fff6ff3f 100644 --- a/make/java/nio/FILES_java.gmk +++ b/make/java/nio/FILES_java.gmk @@ -160,7 +160,6 @@ FILES_src = \ \ sun/nio/ByteBuffered.java \ \ - sun/nio/ch/AbstractFuture.java \ sun/nio/ch/AbstractPollArrayWrapper.java \ sun/nio/ch/AllocatedNativeObject.java \ sun/nio/ch/AsynchronousChannelGroupImpl.java \ diff --git a/make/netbeans/jdwpgen/build.xml b/make/netbeans/jdwpgen/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..da67672e2afd96ffcda4d0dcd79f85ca28ccc353 --- /dev/null +++ b/make/netbeans/jdwpgen/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + Builds, tests, and runs the project jdwpgen. + + + diff --git a/make/netbeans/jdwpgen/nbproject/build-impl.xml b/make/netbeans/jdwpgen/nbproject/build-impl.xml new file mode 100644 index 0000000000000000000000000000000000000000..9997d00d9e7f60964325dfd5b20d4f64ebd0dec7 --- /dev/null +++ b/make/netbeans/jdwpgen/nbproject/build-impl.xml @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + diff --git a/make/netbeans/jdwpgen/nbproject/findbugs.settings b/make/netbeans/jdwpgen/nbproject/findbugs.settings new file mode 100644 index 0000000000000000000000000000000000000000..cb205d1aa214620da993b3eda013f4bd80f4ce4e --- /dev/null +++ b/make/netbeans/jdwpgen/nbproject/findbugs.settings @@ -0,0 +1,72 @@ +#FindBugs User Preferences +#Mon Jun 15 13:37:16 PDT 2009 +detectorAbnormalFinallyBlockReturn=AbnormalFinallyBlockReturn|false +detectorAbstractClassEmptyMethods=AbstractClassEmptyMethods|false +detectorAbstractOverriddenMethod=AbstractOverriddenMethod|false +detectorArrayBasedCollections=ArrayBasedCollections|false +detectorArrayWrappedCallByReference=ArrayWrappedCallByReference|false +detectorBloatedAssignmentScope=BloatedAssignmentScope|false +detectorBloatedSynchronizedBlock=BloatedSynchronizedBlock|false +detectorClassEnvy=ClassEnvy|false +detectorCollectStatistics=CollectStatistics|false +detectorConfusingAutoboxedOverloading=ConfusingAutoboxedOverloading|false +detectorConstantListIndex=ConstantListIndex|false +detectorCopiedOverriddenMethod=CopiedOverriddenMethod|false +detectorCustomBuiltXML=CustomBuiltXML|false +detectorCyclomaticComplexity=CyclomaticComplexity|false +detectorDateComparison=DateComparison|false +detectorDeclaredRuntimeException=DeclaredRuntimeException|false +detectorDeletingWhileIterating=DeletingWhileIterating|false +detectorDubiousListCollection=DubiousListCollection|false +detectorFieldCouldBeLocal=FieldCouldBeLocal|false +detectorFinalParameters=FinalParameters|false +detectorFloatingPointLoops=FloatingPointLoops|false +detectorInefficientStringBuffering=InefficientStringBuffering|false +detectorInheritanceTypeChecking=InheritanceTypeChecking|false +detectorJDBCVendorReliance=JDBCVendorReliance|false +detectorListIndexedIterating=ListIndexedIterating|false +detectorLiteralStringComparison=LiteralStringComparison|false +detectorLocalSynchronizedCollection=LocalSynchronizedCollection|false +detectorLostExceptionStackTrace=LostExceptionStackTrace|false +detectorManualArrayCopy=ManualArrayCopy|false +detectorMethodReturnsConstant=MethodReturnsConstant|false +detectorNeedlessAutoboxing=NeedlessAutoboxing|false +detectorNeedlessCustomSerialization=NeedlessCustomSerialization|false +detectorNeedlessInstanceRetrieval=NeedlessInstanceRetrieval|false +detectorNeedlessMemberCollectionSynchronization=NeedlessMemberCollectionSynchronization|false +detectorNonCollectionMethodUse=NonCollectionMethodUse|false +detectorNonOwnedSynchronization=NonOwnedSynchronization|false +detectorNonRecycleableTaglibs=NonRecycleableTaglibs|false +detectorOrphanedDOMNode=OrphanedDOMNode|false +detectorOverlyConcreteParameter=OverlyConcreteParameter|false +detectorParallelLists=ParallelLists|false +detectorPartiallyConstructedObjectAccess=PartiallyConstructedObjectAccess|false +detectorPossibleIncompleteSerialization=PossibleIncompleteSerialization|false +detectorPossibleMemoryBloat=PossibleMemoryBloat|false +detectorPossiblyRedundantMethodCalls=PossiblyRedundantMethodCalls|false +detectorSQLInLoop=SQLInLoop|false +detectorSection508Compliance=Section508Compliance|false +detectorSillynessPotPourri=SillynessPotPourri|false +detectorSloppyClassReflection=SloppyClassReflection|false +detectorSluggishGui=SluggishGui|false +detectorSpoiledChildInterfaceImplementor=SpoiledChildInterfaceImplementor|false +detectorSpuriousThreadStates=SpuriousThreadStates|false +detectorStaticArrayCreatedInMethod=StaticArrayCreatedInMethod|false +detectorStaticMethodInstanceInvocation=StaticMethodInstanceInvocation|false +detectorSuspiciousComparatorReturnValues=SuspiciousComparatorReturnValues|false +detectorSuspiciousJDKVersionUse=SuspiciousJDKVersionUse|false +detectorSuspiciousWaitOnConcurrentObject=SuspiciousWaitOnConcurrentObject|false +detectorSyncCollectionIterators=SyncCollectionIterators|false +detectorTailRecursion=TailRecursion|false +detectorUnnecessaryStoreBeforeReturn=UnnecessaryStoreBeforeReturn|false +detectorUnrelatedCollectionContents=UnrelatedCollectionContents|false +detectorUnrelatedReturnValues=UnrelatedReturnValues|false +detectorUseAddAll=UseAddAll|false +detectorUseCharacterParameterizedMethod=UseCharacterParameterizedMethod|false +detectorUseEnumCollections=UseEnumCollections|false +detectorUseSplit=UseSplit|false +detectorUseToArray=UseToArray|false +detector_threshold=2 +effort=default +filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false +filter_settings_neg=| diff --git a/make/netbeans/jdwpgen/nbproject/genfiles.properties b/make/netbeans/jdwpgen/nbproject/genfiles.properties new file mode 100644 index 0000000000000000000000000000000000000000..a82838d7b0fbe52e366766c26cda718f16af29d6 --- /dev/null +++ b/make/netbeans/jdwpgen/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=b40e775f +build.xml.script.CRC32=af8dc3cb +build.xml.stylesheet.CRC32=958a1d3e +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=b40e775f +nbproject/build-impl.xml.script.CRC32=624d12c5 +nbproject/build-impl.xml.stylesheet.CRC32=65b8de21 diff --git a/make/netbeans/jdwpgen/nbproject/project.properties b/make/netbeans/jdwpgen/nbproject/project.properties new file mode 100644 index 0000000000000000000000000000000000000000..19b2cffc99188b3234f33d26ee5e7d73b3df6b9f --- /dev/null +++ b/make/netbeans/jdwpgen/nbproject/project.properties @@ -0,0 +1,65 @@ +application.title=jdwpgen +application.vendor=sun +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/jdwpgen.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +file.reference.tools-jdwpgen=../../tools/src/build/tools/jdwpgen +file.reference.tools-src=../../tools/src +includes=build/tools/jdwpgen/** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs=-Xlint:all +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=true +javadoc.nonavbar=true +javadoc.notree=true +javadoc.private=true +javadoc.splitindex=false +javadoc.use=false +javadoc.version=false +javadoc.windowtitle= +main.class=jdwpgen.Main +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.src.dir=${file.reference.tools-src} +test.src.dir=test diff --git a/make/netbeans/jdwpgen/nbproject/project.xml b/make/netbeans/jdwpgen/nbproject/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..c7bf8edefc0d6065840b7d52094b50be281997c8 --- /dev/null +++ b/make/netbeans/jdwpgen/nbproject/project.xml @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2seproject + + + jdwpgen + 1.6.5 + + + + + + + + + diff --git a/make/netbeans/jdwpgen/nbproject/sqe.properties b/make/netbeans/jdwpgen/nbproject/sqe.properties new file mode 100644 index 0000000000000000000000000000000000000000..978ef5bc0139ccd7d0efc5d28ec3bd94f0c91812 --- /dev/null +++ b/make/netbeans/jdwpgen/nbproject/sqe.properties @@ -0,0 +1,2 @@ +#Path to FindbugsSettingsFile (relative) +findbugs.settings.file=findbugs.settings diff --git a/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java b/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java index 442019676dc5949c31ccdde8503f0de2bb6f81fa..ea362356fc318a22c0c718cb7ab6b9a60db676ae 100644 --- a/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java +++ b/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java @@ -30,7 +30,7 @@ import java.io.*; abstract class AbstractNamedNode extends Node { - NameNode nameNode; + NameNode nameNode = null; String name; public String name() { diff --git a/make/tools/src/build/tools/jdwpgen/AltNode.java b/make/tools/src/build/tools/jdwpgen/AltNode.java index b4aeae90b583931c32fd25d549104552c83f9cdc..76b5ed423ffe585674bd48b5318fefea5c103d11 100644 --- a/make/tools/src/build/tools/jdwpgen/AltNode.java +++ b/make/tools/src/build/tools/jdwpgen/AltNode.java @@ -30,7 +30,7 @@ import java.io.*; class AltNode extends AbstractGroupNode implements TypeNode { - SelectNode select; + SelectNode select = null; void constrain(Context ctx) { super.constrain(ctx); diff --git a/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java b/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java index 56ca041c4ff364cb7c214913e7dd08c2a92daf26..86196612d37d5c5f463444ea23d93e48877d2e1b 100644 --- a/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java +++ b/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java @@ -33,13 +33,7 @@ class ConstantSetNode extends AbstractNamedNode { /** * The mapping between a constant and its value. */ - protected static Map constantMap; - - ConstantSetNode(){ - if (constantMap == null) { - constantMap = new HashMap(); - } - } + protected static final Map constantMap = new HashMap(); void prune() { List addons = new ArrayList(); @@ -95,9 +89,6 @@ class ConstantSetNode extends AbstractNamedNode { } public static String getConstant(String key){ - if (constantMap == null) { - return ""; - } String com = constantMap.get(key); if(com == null){ return ""; diff --git a/make/tools/src/build/tools/jdwpgen/Main.java b/make/tools/src/build/tools/jdwpgen/Main.java index 2562dd10da63c2e3388f8eaba82a768f0d60942e..c7ce8e3c86d0b63905d254f31fc74f00f3d5b876 100644 --- a/make/tools/src/build/tools/jdwpgen/Main.java +++ b/make/tools/src/build/tools/jdwpgen/Main.java @@ -25,13 +25,11 @@ package build.tools.jdwpgen; -import java.util.*; import java.io.*; class Main { static String specSource; - static Map nameMap = new HashMap(); static boolean genDebug = true; static void usage() { @@ -43,7 +41,6 @@ class Main { System.err.println("-doc "); System.err.println("-jdi "); System.err.println("-include "); - System.exit(1); } public static void main(String args[]) throws IOException { @@ -66,6 +63,7 @@ class Main { } else { System.err.println("Invalid option: " + arg); usage(); + return; } } else { specSource = arg; @@ -75,6 +73,7 @@ class Main { if (reader == null) { System.err.println(" must be specified"); usage(); + return; } Parse parse = new Parse(reader); diff --git a/make/tools/src/build/tools/jdwpgen/Node.java b/make/tools/src/build/tools/jdwpgen/Node.java index 2f79688186a49c3bf44cc88003e8a5e497541689..4dd33d07a11e680a52a35f13bb47a39bb9f7f254 100644 --- a/make/tools/src/build/tools/jdwpgen/Node.java +++ b/make/tools/src/build/tools/jdwpgen/Node.java @@ -36,7 +36,7 @@ abstract class Node { int lineno; List commentList = new ArrayList(); Node parent = null; - Context context; + Context context = null; static final int maxStructIndent = 5; static int structIndent = 0; // horrible hack @@ -82,7 +82,7 @@ abstract class Node { } void indent(PrintWriter writer, int depth) { - for (int i = depth; i > 0; --i) { + for (int i = 0; i < depth; i++) { writer.print(" "); } } @@ -195,6 +195,6 @@ abstract class Node { System.err.println(Main.specSource + ":" + lineno + ": " + kind + " - " + errmsg); System.err.println(); - System.exit(1); + throw new RuntimeException("Error: " + errmsg); } } diff --git a/make/tools/src/build/tools/jdwpgen/Parse.java b/make/tools/src/build/tools/jdwpgen/Parse.java index f5e3ebb9ed485ae019d6f9606c00486b078b84ec..aac5b1f5290f1b092fe3ac8235ba87df4fa5836a 100644 --- a/make/tools/src/build/tools/jdwpgen/Parse.java +++ b/make/tools/src/build/tools/jdwpgen/Parse.java @@ -146,8 +146,12 @@ class Parse { Node node = (Node)proto.getClass().newInstance(); node.set(kind, list, izer.lineno()); return node; - } catch (Exception exc) { + } catch (InstantiationException exc) { error(exc.toString()); + return null; + } catch (IllegalAccessException exc) { + error(exc.toString()); + return null; } } } else { @@ -166,6 +170,6 @@ class Parse { void error(String errmsg) { System.err.println(Main.specSource + ":" + izer.lineno() + ": " + errmsg); - System.exit(1); + throw new RuntimeException("Error: " + errmsg); } } diff --git a/make/tools/src/build/tools/jdwpgen/RepeatNode.java b/make/tools/src/build/tools/jdwpgen/RepeatNode.java index 107072a52d3c57e6a2d4d883d93122ba02d952b6..c841b9131549691851fe761531af33c323b5dd96 100644 --- a/make/tools/src/build/tools/jdwpgen/RepeatNode.java +++ b/make/tools/src/build/tools/jdwpgen/RepeatNode.java @@ -30,7 +30,7 @@ import java.io.*; class RepeatNode extends AbstractTypeNode { - Node member; + Node member = null; void constrain(Context ctx) { super.constrain(ctx); diff --git a/make/tools/src/build/tools/jdwpgen/SelectNode.java b/make/tools/src/build/tools/jdwpgen/SelectNode.java index cfe0c97cfe6e2738da3138c266562dd542ca5abd..dd57afb7b07ea97e6246d38b6ad4b4a37b2723bf 100644 --- a/make/tools/src/build/tools/jdwpgen/SelectNode.java +++ b/make/tools/src/build/tools/jdwpgen/SelectNode.java @@ -30,7 +30,7 @@ import java.io.*; class SelectNode extends AbstractGroupNode implements TypeNode { - AbstractSimpleTypeNode typeNode; + AbstractSimpleTypeNode typeNode = null; void prune() { super.prune(); diff --git a/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java b/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java index 9a21dc9ddfe895962c22b1d65a4d94e5dfbd3e79..43d38d935ddeb896c5984783604303fe3990126f 100644 --- a/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java +++ b/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java @@ -129,7 +129,7 @@ public class TextCallbackHandler implements CallbackHandler { System.err.print(pc.getPrompt()); System.err.flush(); - pc.setPassword(Password.readPassword(System.in)); + pc.setPassword(Password.readPassword(System.in, pc.isEchoOn())); } else if (callbacks[i] instanceof ConfirmationCallback) { confirmation = (ConfirmationCallback) callbacks[i]; diff --git a/src/share/classes/com/sun/security/sasl/Provider.java b/src/share/classes/com/sun/security/sasl/Provider.java index c1900e582fb3fd503fa17eba50d251e442debd88..effc5b7bbc39b4d9d50c8eb6c504bc03a87c9938 100644 --- a/src/share/classes/com/sun/security/sasl/Provider.java +++ b/src/share/classes/com/sun/security/sasl/Provider.java @@ -51,7 +51,7 @@ public final class Provider extends java.security.Provider { " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)"; public Provider() { - super("SunSASL", 1.5, info); + super("SunSASL", 1.7d, info); AccessController.doPrivileged(new PrivilegedAction() { public Void run() { diff --git a/src/share/classes/java/lang/EnumConstantNotPresentException.java b/src/share/classes/java/lang/EnumConstantNotPresentException.java index 4807691b2106ede61d0e0403e9213d6aed944cee..a16b0e5bdfb820371bada91ed6bc4d4c6362b036 100644 --- a/src/share/classes/java/lang/EnumConstantNotPresentException.java +++ b/src/share/classes/java/lang/EnumConstantNotPresentException.java @@ -28,8 +28,12 @@ package java.lang; /** * Thrown when an application tries to access an enum constant by name * and the enum type contains no constant with the specified name. + * This exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class EnumConstantNotPresentException extends RuntimeException { diff --git a/src/share/classes/java/lang/String.java b/src/share/classes/java/lang/String.java index 316da645f3c8dfb16eab5681c957b2aa92a26bd2..e4327434c389d48259d59f0ec5cc0759b36bfb1c 100644 --- a/src/share/classes/java/lang/String.java +++ b/src/share/classes/java/lang/String.java @@ -2301,6 +2301,54 @@ public final class String * @spec JSR-51 */ public String[] split(String regex, int limit) { + /* fastpath if the regex is a + (1)one-char String and this character is not one of the + RegEx's meta characters ".$|()[{^?*+\\", or + (2)two-char String and the first char is the backslash and + the second is not the ascii digit or ascii letter. + */ + char ch = 0; + if (((regex.count == 1 && + ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || + (regex.length() == 2 && + regex.charAt(0) == '\\' && + (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && + ((ch-'a')|('z'-ch)) < 0 && + ((ch-'A')|('Z'-ch)) < 0)) && + (ch < Character.MIN_HIGH_SURROGATE || + ch > Character.MAX_LOW_SURROGATE)) + { + int off = 0; + int next = 0; + boolean limited = limit > 0; + ArrayList list = new ArrayList(); + while ((next = indexOf(ch, off)) != -1) { + if (!limited || list.size() < limit - 1) { + list.add(substring(off, next)); + off = next + 1; + } else { // last one + //assert (list.size() == limit - 1); + list.add(substring(off, count)); + off = count; + break; + } + } + // If no match was found, return this + if (off == 0) + return new String[] { this }; + + // Add remaining segment + if (!limited || list.size() < limit) + list.add(substring(off, count)); + + // Construct result + int resultSize = list.size(); + if (limit == 0) + while (resultSize > 0 && list.get(resultSize-1).length() == 0) + resultSize--; + String[] result = new String[resultSize]; + return list.subList(0, resultSize).toArray(result); + } return Pattern.compile(regex).split(this, limit); } diff --git a/src/share/classes/java/lang/TypeNotPresentException.java b/src/share/classes/java/lang/TypeNotPresentException.java index d7fa0d6bdeb7bb0a24a28608e0ea47ff82ce2bd1..72b708393d17235497693ed9f64d08b41752a0af 100644 --- a/src/share/classes/java/lang/TypeNotPresentException.java +++ b/src/share/classes/java/lang/TypeNotPresentException.java @@ -35,8 +35,12 @@ package java.lang; *

Note that this exception may be used when undefined type variables * are accessed as well as when types (e.g., classes, interfaces or * annotation types) are loaded. + * In particular, this exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class TypeNotPresentException extends RuntimeException { diff --git a/src/share/classes/java/lang/annotation/AnnotationFormatError.java b/src/share/classes/java/lang/annotation/AnnotationFormatError.java index 0bc2fd15169b94f52bffebed8a01a8800d5baf10..0263907cdba4f906752a28df59de911dd984941d 100644 --- a/src/share/classes/java/lang/annotation/AnnotationFormatError.java +++ b/src/share/classes/java/lang/annotation/AnnotationFormatError.java @@ -28,8 +28,12 @@ package java.lang.annotation; /** * Thrown when the annotation parser attempts to read an annotation * from a class file and determines that the annotation is malformed. + * This error can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class AnnotationFormatError extends Error { diff --git a/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java b/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java index c4cb7534c310f8ee025f853820e857df707eaa73..830b1f98dfe2ad2f9741b860e96f9a4973ced298 100644 --- a/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java +++ b/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java @@ -30,8 +30,12 @@ import java.lang.reflect.Method; * Thrown to indicate that a program has attempted to access an element of * an annotation whose type has changed after the annotation was compiled * (or serialized). + * This exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class AnnotationTypeMismatchException extends RuntimeException { diff --git a/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java b/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java index 04070a1bbd4a2700522a9834ab04e45b6e187317..9d5f43e1ad61503fd28b5f0447161c00ee0d5544 100644 --- a/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java +++ b/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java @@ -30,8 +30,12 @@ package java.lang.annotation; * an annotation type that was added to the annotation type definition after * the annotation was compiled (or serialized). This exception will not be * thrown if the new element has a default value. + * This exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class IncompleteAnnotationException extends RuntimeException { diff --git a/src/share/classes/java/lang/reflect/AnnotatedElement.java b/src/share/classes/java/lang/reflect/AnnotatedElement.java index 41436d63c0e21a8561fa5b3a4a96aa4b86652f00..0601168a0a064741c976b02a8d9c1e0799a55408 100644 --- a/src/share/classes/java/lang/reflect/AnnotatedElement.java +++ b/src/share/classes/java/lang/reflect/AnnotatedElement.java @@ -50,6 +50,11 @@ import java.lang.annotation.Annotation; * java.lang.annotation.AnnotationTypeMismatchException} or an * {@link java.lang.annotation.IncompleteAnnotationException}. * + * @see java.lang.EnumConstantNotPresentException + * @see java.lang.TypeNotPresentException + * @see java.lang.annotation.AnnotationFormatError + * @see java.lang.annotation.AnnotationTypeMismatchException + * @see java.lang.annotation.IncompleteAnnotationException * @since 1.5 * @author Josh Bloch */ diff --git a/src/share/classes/java/nio/channels/AsynchronousByteChannel.java b/src/share/classes/java/nio/channels/AsynchronousByteChannel.java index 7bc433574792ff82b734dbaf44f68e61f8b9bedd..2b2c8226d4f138cdb7e1aa05236d688a7f9dd7fc 100644 --- a/src/share/classes/java/nio/channels/AsynchronousByteChannel.java +++ b/src/share/classes/java/nio/channels/AsynchronousByteChannel.java @@ -56,18 +56,18 @@ public interface AsynchronousByteChannel /** * Reads a sequence of bytes from this channel into the given buffer. * - *

This method initiates an operation to read a sequence of bytes from - * this channel into the given buffer. The method returns a {@link Future} - * representing the pending result of the operation. The result of the - * operation, obtained by invoking the {@code Future} 's {@link - * Future#get() get} method, is the number of bytes read or {@code -1} if - * all bytes have been read and the channel has reached end-of-stream. - * - *

This method initiates a read operation to read up to r bytes - * from the channel, where r is the number of bytes remaining in the - * buffer, that is, {@code dst.remaining()} at the time that the read is - * attempted. Where r is 0, the read operation completes immediately - * with a result of {@code 0} without initiating an I/O operation. + *

This method initiates an asynchronous read operation to read a + * sequence of bytes from this channel into the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the read + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes read or {@code -1} if no bytes could be + * read because the channel has reached end-of-stream. + * + *

The read operation may read up to r bytes from the channel, + * where r is the number of bytes remaining in the buffer, that is, + * {@code dst.remaining()} at the time that the read is attempted. Where + * r is 0, the read operation completes immediately with a result of + * {@code 0} without initiating an I/O operation. * *

Suppose that a byte sequence of length n is read, where * 0 < n <= r. @@ -79,44 +79,46 @@ public interface AsynchronousByteChannel * p + n; its limit will not have changed. * *

Buffers are not safe for use by multiple concurrent threads so care - * should be taken to not to access the buffer until the operaton has completed. + * should be taken to not access the buffer until the operation has + * completed. * *

This method may be invoked at any time. Some channel types may not * allow more than one read to be outstanding at any given time. If a thread * initiates a read operation before a previous read operation has * completed then a {@link ReadPendingException} will be thrown. * - *

The handler parameter is used to specify a {@link - * CompletionHandler}. When the read operation completes the handler's - * {@link CompletionHandler#completed completed} method is executed. - * - * * @param dst * The buffer into which bytes are to be transferred * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The completion handler object; can be {@code null} - * - * @return A Future representing the result of the operation + * The completion handler * * @throws IllegalArgumentException * If the buffer is read-only * @throws ReadPendingException * If the channel does not allow more than one read to be outstanding * and a previous read has not completed + * @throws ShutdownChannelGroupException + * If the channel is associated with a {@link AsynchronousChannelGroup + * group} that has terminated */ - Future read(ByteBuffer dst, - A attachment, - CompletionHandler handler); + void read(ByteBuffer dst, + A attachment, + CompletionHandler handler); /** * Reads a sequence of bytes from this channel into the given buffer. * - *

An invocation of this method of the form c.read(dst) - * behaves in exactly the same manner as the invocation - *

-     * c.read(dst, null, null);
+ *

This method initiates an asynchronous read operation to read a + * sequence of bytes from this channel into the given buffer. The method + * behaves in exactly the same manner as the {@link + * #read(ByteBuffer,Object,CompletionHandler) + * read(ByteBuffer,Object,CompletionHandler)} method except that instead + * of specifying a completion handler, this method returns a {@code Future} + * representing the pending result. The {@code Future}'s {@link Future#get() + * get} method returns the number of bytes read or {@code -1} if no bytes + * could be read because the channel has reached end-of-stream. * * @param dst * The buffer into which bytes are to be transferred @@ -134,17 +136,17 @@ public interface AsynchronousByteChannel /** * Writes a sequence of bytes to this channel from the given buffer. * - *

This method initiates an operation to write a sequence of bytes to - * this channel from the given buffer. This method returns a {@link - * Future} representing the pending result of the operation. The result - * of the operation, obtained by invoking the Future's {@link - * Future#get() get} method, is the number of bytes written, possibly zero. + *

This method initiates an asynchronous write operation to write a + * sequence of bytes to this channel from the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the write + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes written. * - *

This method initiates a write operation to write up to r bytes - * to the channel, where r is the number of bytes remaining in the - * buffer, that is, {@code src.remaining()} at the moment the write is - * attempted. Where r is 0, the write operation completes immediately - * with a result of {@code 0} without initiating an I/O operation. + *

The write operation may write up to r bytes to the channel, + * where r is the number of bytes remaining in the buffer, that is, + * {@code src.remaining()} at the time that the write is attempted. Where + * r is 0, the write operation completes immediately with a result of + * {@code 0} without initiating an I/O operation. * *

Suppose that a byte sequence of length n is written, where * 0 < n <= r. @@ -156,41 +158,43 @@ public interface AsynchronousByteChannel * p + n; its limit will not have changed. * *

Buffers are not safe for use by multiple concurrent threads so care - * should be taken to not to access the buffer until the operaton has completed. + * should be taken to not access the buffer until the operation has + * completed. * *

This method may be invoked at any time. Some channel types may not * allow more than one write to be outstanding at any given time. If a thread * initiates a write operation before a previous write operation has * completed then a {@link WritePendingException} will be thrown. * - *

The handler parameter is used to specify a {@link - * CompletionHandler}. When the write operation completes the handler's - * {@link CompletionHandler#completed completed} method is executed. - * * @param src * The buffer from which bytes are to be retrieved * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The completion handler object; can be {@code null} - * - * @return A Future representing the result of the operation + * The completion handler object * * @throws WritePendingException * If the channel does not allow more than one write to be outstanding * and a previous write has not completed + * @throws ShutdownChannelGroupException + * If the channel is associated with a {@link AsynchronousChannelGroup + * group} that has terminated */ - Future write(ByteBuffer src, - A attachment, - CompletionHandler handler); + void write(ByteBuffer src, + A attachment, + CompletionHandler handler); /** * Writes a sequence of bytes to this channel from the given buffer. * - *

An invocation of this method of the form c.write(src) - * behaves in exactly the same manner as the invocation - *

-     * c.write(src, null, null);
+ *

This method initiates an asynchronous write operation to write a + * sequence of bytes to this channel from the given buffer. The method + * behaves in exactly the same manner as the {@link + * #write(ByteBuffer,Object,CompletionHandler) + * write(ByteBuffer,Object,CompletionHandler)} method except that instead + * of specifying a completion handler, this method returns a {@code Future} + * representing the pending result. The {@code Future}'s {@link Future#get() + * get} method returns the number of bytes written. * * @param src * The buffer from which bytes are to be retrieved diff --git a/src/share/classes/java/nio/channels/AsynchronousChannel.java b/src/share/classes/java/nio/channels/AsynchronousChannel.java index f3e4ffe4ea5ac488b3ed76c0417c64523f058133..69ee8bd65d7cf18da2674d1b34b654b34590d45a 100644 --- a/src/share/classes/java/nio/channels/AsynchronousChannel.java +++ b/src/share/classes/java/nio/channels/AsynchronousChannel.java @@ -34,7 +34,8 @@ import java.util.concurrent.Future; // javadoc * *

    *
  1. {@link Future}<V> operation(...)
  2. - *
  3. Future<V> operation(... A attachment, {@link CompletionHandler}<V,? super A> handler)
  4. + *
  5. void operation(... A attachment, {@link
    + *   CompletionHandler}<V,? super A> handler)
  6. *
* * where operation is the name of the I/O operation (read or write for @@ -48,7 +49,7 @@ import java.util.concurrent.Future; // javadoc * interface may be used to check if the operation has completed, wait for its * completion, and to retrieve the result. In the second form, a {@link * CompletionHandler} is invoked to consume the result of the I/O operation when - * it completes, fails, or is cancelled. + * it completes or fails. * *

A channel that implements this interface is asynchronously * closeable: If an I/O operation is outstanding on the channel and the @@ -63,33 +64,33 @@ import java.util.concurrent.Future; // javadoc *

Cancellation

* *

The {@code Future} interface defines the {@link Future#cancel cancel} - * method to cancel execution of a task. - * - *

Where the {@code cancel} method is invoked with the {@code + * method to cancel execution. This causes all threads waiting on the result of + * the I/O operation to throw {@link java.util.concurrent.CancellationException}. + * Whether the underlying I/O operation can be cancelled is highly implementation + * specific and therefore not specified. Where cancellation leaves the channel, + * or the entity to which it is connected, in an inconsistent state, then the + * channel is put into an implementation specific error state that + * prevents further attempts to initiate I/O operations that are similar + * to the operation that was cancelled. For example, if a read operation is + * cancelled but the implementation cannot guarantee that bytes have not been + * read from the channel then it puts the channel into an error state; further + * attempts to initiate a {@code read} operation cause an unspecified runtime + * exception to be thrown. Similarly, if a write operation is cancelled but the + * implementation cannot guarantee that bytes have not been written to the + * channel then subsequent attempts to initiate a {@code write} will fail with + * an unspecified runtime exception. + * + *

Where the {@link Future#cancel cancel} method is invoked with the {@code * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation - * may be interrupted by closing the channel. This will cause any other I/O - * operations outstanding on the channel to complete with the exception {@link - * AsynchronousCloseException}. - * - *

If a {@code CompletionHandler} is specified when initiating an I/O - * operation, and the {@code cancel} method is invoked to cancel the I/O - * operation before it completes, then the {@code CompletionHandler}'s {@link - * CompletionHandler#cancelled cancelled} method is invoked. - * - *

If an implementation of this interface supports a means to cancel I/O - * operations, and where cancellation may leave the channel, or the entity to - * which it is connected, in an inconsistent state, then the channel is put into - * an implementation specific error state that prevents further - * attempts to initiate I/O operations on the channel. For example, if a read - * operation is cancelled but the implementation cannot guarantee that bytes - * have not been read from the channel then it puts the channel into error state - * state; further attempts to initiate a {@code read} operation causes an - * unspecified runtime exception to be thrown. + * may be interrupted by closing the channel. In that case all threads waiting + * on the result of the I/O operation throw {@code CancellationException} and + * any other I/O operations outstanding on the channel complete with the + * exception {@link AsynchronousCloseException}. * *

Where the {@code cancel} method is invoked to cancel read or write - * operations then it recommended that all buffers used in the I/O operations be - * discarded or care taken to ensure that the buffers are not accessed while the - * channel remains open. + * operations then it is recommended that all buffers used in the I/O operations + * be discarded or care taken to ensure that the buffers are not accessed while + * the channel remains open. * * @since 1.7 */ @@ -102,7 +103,7 @@ public interface AsynchronousChannel * *

Any outstanding asynchronous operations upon this channel will * complete with the exception {@link AsynchronousCloseException}. After a - * channel is closed then further attempts to initiate asynchronous I/O + * channel is closed, further attempts to initiate asynchronous I/O * operations complete immediately with cause {@link ClosedChannelException}. * *

This method otherwise behaves exactly as specified by the {@link diff --git a/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java b/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java index 65b90d0f29d4ce611f31b34dedd6f5e60c55a70d..a229ce627376d8de83af6a7d5fb1870a9ccd7567 100644 --- a/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java +++ b/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java @@ -109,19 +109,13 @@ import java.nio.ByteBuffer; * // print the source address of all packets that we receive * dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() { * public void completed(SocketAddress sa, ByteBuffer buffer) { - * try { - * System.out.println(sa); - * - * buffer.clear(); - * dc.receive(buffer, buffer, this); - * } catch (...) { ... } + * System.out.println(sa); + * buffer.clear(); + * dc.receive(buffer, buffer, this); * } * public void failed(Throwable exc, ByteBuffer buffer) { * ... * } - * public void cancelled(ByteBuffer buffer) { - * ... - * } * }); * * @@ -314,10 +308,10 @@ public abstract class AsynchronousDatagramChannel /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the source address of the datagram upon successful completion. + *

This method initiates the receiving of a datagram into the given + * buffer. The {@code handler} parameter is a completion handler that is + * invoked when the receive operation completes (or fails). The result + * passed to the completion handler is the datagram's source address. * *

The datagram is transferred into the given byte buffer starting at * its current position, as if by a regular {@link AsynchronousByteChannel#read @@ -350,28 +344,26 @@ public abstract class AsynchronousDatagramChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the timeout is negative or the buffer is read-only * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future receive(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void receive(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the source address of the datagram upon successful completion. + *

This method initiates the receiving of a datagram into the given + * buffer. The {@code handler} parameter is a completion handler that is + * invoked when the receive operation completes (or fails). The result + * passed to the completion handler is the datagram's source address. * *

This method is equivalent to invoking {@link * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a @@ -382,34 +374,30 @@ public abstract class AsynchronousDatagramChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the buffer is read-only * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public final Future receive(ByteBuffer dst, - A attachment, - CompletionHandler handler) + public final void receive(ByteBuffer dst, + A attachment, + CompletionHandler handler) { - return receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the source address of the datagram upon successful completion. - * - *

This method is equivalent to invoking {@link - * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a - * timeout of {@code 0L}, and an attachment and completion handler - * of {@code null}. + *

This method initiates the receiving of a datagram into the given + * buffer. The method behaves in exactly the same manner as the {@link + * #receive(ByteBuffer,Object,CompletionHandler) + * receive(ByteBuffer,Object,CompletionHandler)} method except that instead + * of specifying a completion handler, this method returns a {@code Future} + * representing the pending result. The {@code Future}'s {@link Future#get() + * get} method returns the datagram's source address. * * @param dst * The buffer into which the datagram is to be transferred @@ -419,95 +407,28 @@ public abstract class AsynchronousDatagramChannel * @throws IllegalArgumentException * If the buffer is read-only */ - public final Future receive(ByteBuffer dst) { - return receive(dst, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future receive(ByteBuffer dst); /** * Sends a datagram via this channel. * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram to the given target address. The result of the operation, obtained - * by invoking the {@code Future}'s {@link Future#get() get} - * method, is the number of bytes sent. - * - *

The datagram is transferred from the byte buffer as if by a regular - * {@link AsynchronousByteChannel#write write} operation. + *

This method initiates sending of a datagram from the given buffer to + * the given address. The {@code handler} parameter is a completion handler + * that is invoked when the send completes (or fails). The result passed to + * the completion handler is the number of bytes sent. * - *

If a timeout is specified and the timeout elapses before the operation - * completes then the operation completes with the exception {@link - * InterruptedByTimeoutException}. When a timeout elapses then the state of - * the {@link ByteBuffer} is not defined. The buffers should be discarded or - * at least care must be taken to ensure that the buffer is not accessed - * while the channel remains open. - * - *

If there is a security manager installed and the channel is not - * connected then this method verifies that the target address and port number - * are permitted by the security manager's {@link SecurityManager#checkConnect - * checkConnect} method. The overhead of this security check can be avoided - * by first connecting the socket via the {@link #connect connect} method. + *

Otherwise this method works in the same manner as the {@link + * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)} + * method. * * @param src * The buffer containing the datagram to be sent * @param target * The address to which the datagram is to be sent - * @param timeout - * The timeout, or {@code 0L} for no timeout - * @param unit - * The time unit of the {@code timeout} argument * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result - * - * @throws UnresolvedAddressException - * If the given remote address is not fully resolved - * @throws UnsupportedAddressTypeException - * If the type of the given remote address is not supported - * @throws IllegalArgumentException - * If the timeout is negative, or if the channel's socket is - * connected to an address that is not equal to {@code target} - * @throws SecurityException - * If a security manager has been installed and it does not permit - * datagrams to be sent to the given address - * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown - */ - public abstract Future send(ByteBuffer src, - SocketAddress target, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); - - /** - * Sends a datagram via this channel. - * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram to the given target address. The result of the operation, obtained - * by invoking the {@code Future}'s {@link Future#get() get} - * method, is the number of bytes sent. - * - *

This method is equivalent to invoking {@link - * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)} - * with a timeout of {@code 0L}. - * - * @param src - * The buffer containing the datagram to be sent - * @param target - * The address to which the datagram is to be sent - * @param attachment - * The object to attach to the I/O operation; can be {@code null} - * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws UnresolvedAddressException * If the given remote address is not fully resolved @@ -520,30 +441,23 @@ public abstract class AsynchronousDatagramChannel * If a security manager has been installed and it does not permit * datagrams to be sent to the given address * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public final Future send(ByteBuffer src, - SocketAddress target, - A attachment, - CompletionHandler handler) - { - return send(src, target, 0L, TimeUnit.MILLISECONDS, attachment, handler); - } + public abstract void send(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler); /** * Sends a datagram via this channel. * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram to the given target address. The result of the operation, obtained - * by invoking the {@code Future}'s {@link Future#get() get} - * method, is the number of bytes sent. - * - *

This method is equivalent to invoking {@link - * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)} - * with a timeout of {@code 0L} and an attachment and completion handler - * of {@code null}. + *

This method initiates sending of a datagram from the given buffer to + * the given address. The method behaves in exactly the same manner as the + * {@link #send(ByteBuffer,SocketAddress,Object,CompletionHandler) + * send(ByteBuffer,SocketAddress,Object,CompletionHandler)} method except + * that instead of specifying a completion handler, this method returns a + * {@code Future} representing the pending result. The {@code Future}'s + * {@link Future#get() get} method returns the number of bytes sent. * * @param src * The buffer containing the datagram to be sent @@ -563,17 +477,15 @@ public abstract class AsynchronousDatagramChannel * If a security manager has been installed and it does not permit * datagrams to be sent to the given address */ - public final Future send(ByteBuffer src, SocketAddress target) { - return send(src, target, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future send(ByteBuffer src, SocketAddress target); /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the number of bytes transferred upon successful completion. + *

This method initiates the receiving of a datagram into the given + * buffer. The {@code handler} parameter is a completion handler that is + * invoked when the receive operation completes (or fails). The result + * passed to the completion handler is number of bytes read. * *

This method may only be invoked if this channel is connected, and it * only accepts datagrams from the peer that the channel is connected too. @@ -599,120 +511,62 @@ public abstract class AsynchronousDatagramChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the timeout is negative or buffer is read-only * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future read(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future read(ByteBuffer dst, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer dst, + A attachment, + CompletionHandler handler) { - return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future read(ByteBuffer dst) { - return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future read(ByteBuffer dst); - /** - * Writes a datagram to this channel. - * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram. The result of the operation, obtained by invoking the - * {@code Future}'s {@link Future#get() get} method, is the - * number of bytes sent. - * - *

The datagram is transferred from the byte buffer as if by a regular - * {@link AsynchronousByteChannel#write write} operation. - * - *

This method may only be invoked if this channel is connected, - * in which case it sends datagrams directly to the socket's peer. Otherwise - * it behaves exactly as specified in the {@link - * AsynchronousByteChannel} interface. - * - *

If a timeout is specified and the timeout elapses before the operation - * completes then the operation completes with the exception {@link - * InterruptedByTimeoutException}. When a timeout elapses then the state of - * the {@link ByteBuffer} is not defined. The buffers should be discarded or - * at least care must be taken to ensure that the buffer is not accessed - * while the channel remains open. - * - * @param src - * The buffer containing the datagram to be sent - * @param timeout - * The timeout, or {@code 0L} for no timeout - * @param unit - * The time unit of the {@code timeout} argument - * @param attachment - * The object to attach to the I/O operation; can be {@code null} - * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result - * - * @throws IllegalArgumentException - * If the timeout is negative - * @throws NotYetConnectedException - * If this channel is not connected - * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown - */ - public abstract Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future write(ByteBuffer src, - A attachment, - CompletionHandler handler) - { - return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); - } + public abstract void write(ByteBuffer src, + A attachment, + CompletionHandler handler); + /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future write(ByteBuffer src) { - return write(src, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future write(ByteBuffer src); } diff --git a/src/share/classes/java/nio/channels/AsynchronousFileChannel.java b/src/share/classes/java/nio/channels/AsynchronousFileChannel.java index a9bff5f16d4be4b7157d4770a21464e575cbe083..9d37b9d8da8d8f69e5231fcac48e30c225113b1d 100644 --- a/src/share/classes/java/nio/channels/AsynchronousFileChannel.java +++ b/src/share/classes/java/nio/channels/AsynchronousFileChannel.java @@ -48,7 +48,12 @@ import java.util.Collections; * *

An asynchronous file channel does not have a current position * within the file. Instead, the file position is specified to each read and - * write operation. + * write methd that initiate asynchronous operations. A {@link CompletionHandler} + * is specified as a parameter and is invoked to consume the result of the I/O + * operation. This class also defines read and write methods that initiate + * asynchronous operations, returning a {@link Future} to represent the pending + * result of the operation. The {@code Future} may be used to check if the + * operation has completed, to wait for its completion. * *

In addition to read and write operations, this class defines the * following operations:

@@ -59,18 +64,11 @@ import java.util.Collections; * out} to the underlying storage device, ensuring that data are not * lost in the event of a system crash.

* - *
  • A region of a file may be {@link FileLock locked} - * against access by other programs.

  • + *
  • A region of a file may be {@link #lock locked} against + * access by other programs.

  • * * * - *

    The {@link #read read}, {@link #write write}, and {@link #lock lock} - * methods defined by this class are asynchronous and return a {@link Future} - * to represent the pending result of the operation. This may be used to check - * if the operation has completed, to wait for its completion, and to retrieve - * the result. These method may optionally specify a {@link CompletionHandler} - * that is invoked to consume the result of the I/O operation when it completes. - * *

    An {@code AsynchronousFileChannel} is associated with a thread pool to * which tasks are submitted to handle I/O events and dispatch to completion * handlers that consume the results of I/O operations on the channel. The @@ -122,22 +120,6 @@ public abstract class AsynchronousFileChannel protected AsynchronousFileChannel() { } - /** - * Closes this channel. - * - *

    If this channel is associated with its own thread pool then closing - * the channel causes the thread pool to shutdown after all actively - * executing completion handlers have completed. No attempt is made to stop - * or interrupt actively completion handlers. - * - *

    This method otherwise behaves exactly as specified by the {@link - * AsynchronousChannel} interface. - * - * @throws IOException {@inheritDoc} - */ - @Override - public abstract void close() throws IOException; - /** * Opens or creates a file for reading and/or writing, returning an * asynchronous file channel to access the file. @@ -215,9 +197,8 @@ public abstract class AsynchronousFileChannel * should be taken when configuring the {@code Executor}. Minimally it * should support an unbounded work queue and should not run tasks on the * caller thread of the {@link ExecutorService#execute execute} method. - * {@link #close Closing} the channel results in the orderly {@link - * ExecutorService#shutdown shutdown} of the executor service. Shutting down - * the executor service by other means results in unspecified behavior. + * Shutting down the executor service while the channel is open results in + * unspecified behavior. * *

    The {@code attrs} parameter is an optional array of file {@link * FileAttribute file-attributes} to set atomically when creating the file. @@ -276,7 +257,8 @@ public abstract class AsynchronousFileChannel *

    An invocation of this method behaves in exactly the same way as the * invocation *

    -     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[]) open}(file, opts, null, new FileAttribute<?>[0]);
    +     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[])
    +     *       open}(file, opts, null, new FileAttribute<?>[0]);
          * 
    * where {@code opts} is a {@code Set} containing the options specified to * this method. @@ -405,10 +387,11 @@ public abstract class AsynchronousFileChannel /** * Acquires a lock on the given region of this channel's file. * - *

    This method initiates an operation to acquire a lock on the given region - * of this channel's file. The method returns a {@code Future} representing - * the pending result of the operation. Its {@link Future#get() get} - * method returns the {@link FileLock} on successful completion. + *

    This method initiates an operation to acquire a lock on the given + * region of this channel's file. The {@code handler} parameter is a + * completion handler that is invoked when the lock is acquired (or the + * operation fails). The result passed to the completion handler is the + * resulting {@code FileLock}. * *

    The region specified by the {@code position} and {@code size} * parameters need not be contained within, or even overlap, the actual @@ -455,9 +438,7 @@ public abstract class AsynchronousFileChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws OverlappingFileLockException * If a lock that overlaps the requested region is already held by @@ -466,26 +447,24 @@ public abstract class AsynchronousFileChannel * @throws IllegalArgumentException * If the preconditions on the parameters do not hold * @throws NonReadableChannelException - * If {@code shared} is true this channel but was not opened for reading + * If {@code shared} is true but this channel was not opened for reading * @throws NonWritableChannelException * If {@code shared} is false but this channel was not opened for writing - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public abstract Future lock(long position, - long size, - boolean shared, - A attachment, - CompletionHandler handler); + public abstract void lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler); /** * Acquires an exclusive lock on this channel's file. * - *

    This method initiates an operation to acquire an exclusive lock on this - * channel's file. The method returns a {@code Future} representing - * the pending result of the operation. Its {@link Future#get() get} - * method returns the {@link FileLock} on successful completion. + *

    This method initiates an operation to acquire a lock on the given + * region of this channel's file. The {@code handler} parameter is a + * completion handler that is invoked when the lock is acquired (or the + * operation fails). The result passed to the completion handler is the + * resulting {@code FileLock}. * *

    An invocation of this method of the form {@code ch.lock(att,handler)} * behaves in exactly the same way as the invocation @@ -496,40 +475,72 @@ public abstract class AsynchronousFileChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws OverlappingFileLockException * If a lock is already held by this Java virtual machine, or there * is already a pending attempt to lock a region * @throws NonWritableChannelException * If this channel was not opened for writing - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public final Future lock(A attachment, - CompletionHandler handler) + public final void lock(A attachment, + CompletionHandler handler) { - return lock(0L, Long.MAX_VALUE, false, attachment, handler); + lock(0L, Long.MAX_VALUE, false, attachment, handler); } + /** + * Acquires a lock on the given region of this channel's file. + * + *

    This method initiates an operation to acquire a lock on the given + * region of this channel's file. The method behaves in exactly the same + * manner as the {@link #lock(long, long, boolean, Object, CompletionHandler)} + * method except that instead of specifying a completion handler, this + * method returns a {@code Future} representing the pending result. The + * {@code Future}'s {@link Future#get() get} method returns the {@link + * FileLock} on successful completion. + * + * @param position + * The position at which the locked region is to start; must be + * non-negative + * @param size + * The size of the locked region; must be non-negative, and the sum + * {@code position} + {@code size} must be non-negative + * @param shared + * {@code true} to request a shared lock, in which case this + * channel must be open for reading (and possibly writing); + * {@code false} to request an exclusive lock, in which case this + * channel must be open for writing (and possibly reading) + * + * @return a {@code Future} object representing the pending result + * + * @throws OverlappingFileLockException + * If a lock is already held by this Java virtual machine, or there + * is already a pending attempt to lock a region + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + * @throws NonReadableChannelException + * If {@code shared} is true but this channel was not opened for reading + * @throws NonWritableChannelException + * If {@code shared} is false but this channel was not opened for writing + */ + public abstract Future lock(long position, long size, boolean shared); + /** * Acquires an exclusive lock on this channel's file. * *

    This method initiates an operation to acquire an exclusive lock on this * channel's file. The method returns a {@code Future} representing the - * pending result of the operation. Its {@link Future#get() get} method - * returns the {@link FileLock} on successful completion. + * pending result of the operation. The {@code Future}'s {@link Future#get() + * get} method returns the {@link FileLock} on successful completion. * *

    An invocation of this method behaves in exactly the same way as the * invocation *

    -     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, null, null)
    +     *     ch.{@link #lock(long,long,boolean) lock}(0L, Long.MAX_VALUE, false)
          * 
    * - * @return A {@code Future} object representing the pending result + * @return a {@code Future} object representing the pending result * * @throws OverlappingFileLockException * If a lock is already held by this Java virtual machine, or there @@ -538,7 +549,7 @@ public abstract class AsynchronousFileChannel * If this channel was not opened for writing */ public final Future lock() { - return lock(0L, Long.MAX_VALUE, false, null, null); + return lock(0L, Long.MAX_VALUE, false); } /** @@ -576,7 +587,7 @@ public abstract class AsynchronousFileChannel * blocked in this method and is attempting to lock an overlapping * region of the same file * @throws NonReadableChannelException - * If {@code shared} is true this channel but was not opened for reading + * If {@code shared} is true but this channel was not opened for reading * @throws NonWritableChannelException * If {@code shared} is false but this channel was not opened for writing * @@ -629,11 +640,10 @@ public abstract class AsynchronousFileChannel * starting at the given file position. * *

    This method initiates the reading of a sequence of bytes from this - * channel into the given buffer, starting at the given file position. This - * method returns a {@code Future} representing the pending result of the - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes read or {@code -1} if the given position is greater than - * or equal to the file's size at the time that the read is attempted. + * channel into the given buffer, starting at the given file position. The + * result of the read is the number of bytes read or {@code -1} if the given + * position is greater than or equal to the file's size at the time that the + * read is attempted. * *

    This method works in the same manner as the {@link * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)} @@ -649,22 +659,17 @@ public abstract class AsynchronousFileChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the position is negative or the buffer is read-only * @throws NonReadableChannelException * If this channel was not opened for reading - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public abstract Future read(ByteBuffer dst, - long position, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler); /** * Reads a sequence of bytes from this channel into the given buffer, @@ -673,13 +678,15 @@ public abstract class AsynchronousFileChannel *

    This method initiates the reading of a sequence of bytes from this * channel into the given buffer, starting at the given file position. This * method returns a {@code Future} representing the pending result of the - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes read or {@code -1} if the given position is greater + * operation. The {@code Future}'s {@link Future#get() get} method returns + * the number of bytes read or {@code -1} if the given position is greater * than or equal to the file's size at the time that the read is attempted. * - *

    This method is equivalent to invoking {@link - * #read(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment} - * and handler parameters set to {@code null}. + *

    This method works in the same manner as the {@link + * AsynchronousByteChannel#read(ByteBuffer)} method, except that bytes are + * read starting at the given file position. If the given file position is + * greater than the file's size at the time that the read is attempted then + * no bytes are read. * * @param dst * The buffer into which bytes are to be transferred @@ -694,20 +701,12 @@ public abstract class AsynchronousFileChannel * @throws NonReadableChannelException * If this channel was not opened for reading */ - public final Future read(ByteBuffer dst, long position) { - return read(dst, position, null, null); - } + public abstract Future read(ByteBuffer dst, long position); /** * Writes a sequence of bytes to this channel from the given buffer, starting * at the given file position. * - *

    This method initiates the writing of a sequence of bytes to this channel - * from the given buffer, starting at the given file position. The method - * returns a {@code Future} representing the pending result of the write - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes written. - * *

    This method works in the same manner as the {@link * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)} * method, except that bytes are written starting at the given file position. @@ -724,36 +723,35 @@ public abstract class AsynchronousFileChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the position is negative * @throws NonWritableChannelException * If this channel was not opened for writing - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public abstract Future write(ByteBuffer src, - long position, - A attachment, - CompletionHandler handler); + public abstract void write(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler); /** * Writes a sequence of bytes to this channel from the given buffer, starting * at the given file position. * - *

    This method initiates the writing of a sequence of bytes to this channel - * from the given buffer, starting at the given file position. The method - * returns a {@code Future} representing the pending result of the write - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes written. + *

    This method initiates the writing of a sequence of bytes to this + * channel from the given buffer, starting at the given file position. The + * method returns a {@code Future} representing the pending result of the + * write operation. The {@code Future}'s {@link Future#get() get} method + * returns the number of bytes written. * - *

    This method is equivalent to invoking {@link - * #write(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment} - * and handler parameters set to {@code null}. + *

    This method works in the same manner as the {@link + * AsynchronousByteChannel#write(ByteBuffer)} method, except that bytes are + * written starting at the given file position. If the given position is + * greater than the file's size, at the time that the write is attempted, + * then the file will be grown to accommodate the new bytes; the values of + * any bytes between the previous end-of-file and the newly-written bytes + * are unspecified. * * @param src * The buffer from which bytes are to be transferred @@ -768,7 +766,5 @@ public abstract class AsynchronousFileChannel * @throws NonWritableChannelException * If this channel was not opened for writing */ - public final Future write(ByteBuffer src, long position) { - return write(src, position, null, null); - } + public abstract Future write(ByteBuffer src, long position); } diff --git a/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java b/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java index 99c56fa59c0f69fb91c83dad385f5df3908e2a1a..9428f1a5ea674995872c5f4bfc5c9aa36c161ede 100644 --- a/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java +++ b/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java @@ -85,9 +85,6 @@ import java.io.IOException; * public void failed(Throwable exc, Void att) { * ... * } - * public void cancelled(Void att) { - * ... - * } * }); * * @@ -240,11 +237,11 @@ public abstract class AsynchronousServerSocketChannel /** * Accepts a connection. * - *

    This method initiates accepting a connection made to this channel's - * socket, returning a {@link Future} representing the pending result - * of the operation. The {@code Future}'s {@link Future#get() get} - * method will return the {@link AsynchronousSocketChannel} for the new - * connection on successful completion. + *

    This method initiates an asynchronous operation to accept a + * connection made to this channel's socket. The {@code handler} parameter is + * a completion handler that is invoked when a connection is accepted (or + * the operation fails). The result passed to the completion handler is + * the {@link AsynchronousSocketChannel} to the new connection. * *

    When a new connection is accepted then the resulting {@code * AsynchronousSocketChannel} will be bound to the same {@link @@ -269,35 +266,35 @@ public abstract class AsynchronousServerSocketChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return an Future object representing the pending result + * The handler for consuming the result * * @throws AcceptPendingException * If an accept operation is already in progress on this channel * @throws NotYetBoundException * If this channel's socket has not yet been bound * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future - accept(A attachment, CompletionHandler handler); + public abstract void accept(A attachment, + CompletionHandler handler); /** * Accepts a connection. * - *

    This method is equivalent to invoking {@link - * #accept(Object,CompletionHandler)} with the {@code attachment} - * and {@code handler} parameters set to {@code null}. + *

    This method initiates an asynchronous operation to accept a + * connection made to this channel's socket. The method behaves in exactly + * the same manner as the {@link #accept(Object, CompletionHandler)} method + * except that instead of specifying a completion handler, this method + * returns a {@code Future} representing the pending result. The {@code + * Future}'s {@link Future#get() get} method returns the {@link + * AsynchronousSocketChannel} to the new connection on successful completion. * - * @return an Future object representing the pending result + * @return a {@code Future} object representing the pending result * * @throws AcceptPendingException * If an accept operation is already in progress on this channel * @throws NotYetBoundException * If this channel's socket has not yet been bound */ - public final Future accept() { - return accept(null, null); - } + public abstract Future accept(); } diff --git a/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java b/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java index b6a5da8105dc10cbe4169c8a2776d114541486c4..a6d80490e1dac3521d5f05af243972a0cf619aca 100644 --- a/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java +++ b/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java @@ -274,14 +274,11 @@ public abstract class AsynchronousSocketChannel /** * Connects this channel. * - *

    This method initiates an operation to connect this channel, returning - * a {@code Future} representing the pending result of the operation. If - * the connection is successfully established then the {@code Future}'s - * {@link Future#get() get} method will return {@code null}. If the - * connection cannot be established then the channel is closed. In that case, - * invoking the {@code get} method throws {@link - * java.util.concurrent.ExecutionException} with an {@code IOException} as - * the cause. + *

    This method initiates an operation to connect this channel. The + * {@code handler} parameter is a completion handler that is invoked when + * the connection is successfully established or connection cannot be + * established. If the connection cannot be established then the channel is + * closed. * *

    This method performs exactly the same security checks as the {@link * java.net.Socket} class. That is, if a security manager has been @@ -294,9 +291,7 @@ public abstract class AsynchronousSocketChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws UnresolvedAddressException * If the given remote address is not fully resolved @@ -307,23 +302,26 @@ public abstract class AsynchronousSocketChannel * @throws ConnectionPendingException * If a connection operation is already in progress on this channel * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated * @throws SecurityException * If a security manager has been installed * and it does not permit access to the given remote endpoint * * @see #getRemoteAddress */ - public abstract Future connect(SocketAddress remote, - A attachment, - CompletionHandler handler); + public abstract void connect(SocketAddress remote, + A attachment, + CompletionHandler handler); /** * Connects this channel. * - *

    This method is equivalent to invoking {@link - * #connect(SocketAddress,Object,CompletionHandler)} with the {@code attachment} - * and handler parameters set to {@code null}. + *

    This method initiates an operation to connect this channel. This + * method behaves in exactly the same manner as the {@link + * #connect(SocketAddress, Object, CompletionHandler)} method except that + * instead of specifying a completion handler, this method returns a {@code + * Future} representing the pending result. The {@code Future}'s {@link + * Future#get() get} method returns {@code null} on successful completion. * * @param remote * The remote address to which this channel is to be connected @@ -342,18 +340,17 @@ public abstract class AsynchronousSocketChannel * If a security manager has been installed * and it does not permit access to the given remote endpoint */ - public final Future connect(SocketAddress remote) { - return connect(remote, null, null); - } + public abstract Future connect(SocketAddress remote); /** * Reads a sequence of bytes from this channel into the given buffer. * - *

    This method initiates the reading of a sequence of bytes from this - * channel into the given buffer, returning a {@code Future} representing - * the pending result of the operation. The {@code Future}'s {@link - * Future#get() get} method returns the number of bytes read or {@code -1} - * if all bytes have been read and channel has reached end-of-stream. + *

    This method initiates an asynchronous read operation to read a + * sequence of bytes from this channel into the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the read + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes read or {@code -1} if no bytes could be + * read because the channel has reached end-of-stream. * *

    If a timeout is specified and the timeout elapses before the operation * completes then the operation completes with the exception {@link @@ -376,9 +373,7 @@ public abstract class AsynchronousSocketChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the {@code timeout} parameter is negative or the buffer is @@ -388,13 +383,13 @@ public abstract class AsynchronousSocketChannel * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future read(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * @throws IllegalArgumentException {@inheritDoc} @@ -402,14 +397,14 @@ public abstract class AsynchronousSocketChannel * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future read(ByteBuffer dst, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer dst, + A attachment, + CompletionHandler handler) { - return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** @@ -419,16 +414,18 @@ public abstract class AsynchronousSocketChannel * If this channel is not yet connected */ @Override - public final Future read(ByteBuffer dst) { - return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future read(ByteBuffer dst); /** * Reads a sequence of bytes from this channel into a subsequence of the * given buffers. This operation, sometimes called a scattering read, * is often useful when implementing network protocols that group data into * segments consisting of one or more fixed-length headers followed by a - * variable-length body. + * variable-length body. The {@code handler} parameter is a completion + * handler that is invoked when the read operation completes (or fails). The + * result passed to the completion handler is the number of bytes read or + * {@code -1} if no bytes could be read because the channel has reached + * end-of-stream. * *

    This method initiates a read of up to r bytes from this channel, * where r is the total number of bytes remaining in the specified @@ -456,11 +453,6 @@ public abstract class AsynchronousSocketChannel * I/O operation is performed with the maximum number of buffers allowed by * the operating system. * - *

    The return value from this method is a {@code Future} representing - * the pending result of the operation. The {@code Future}'s {@link - * Future#get() get} method returns the number of bytes read or {@code -1L} - * if all bytes have been read and the channel has reached end-of-stream. - * *

    If a timeout is specified and the timeout elapses before the operation * completes then it completes with the exception {@link * InterruptedByTimeoutException}. Where a timeout occurs, and the @@ -485,9 +477,7 @@ public abstract class AsynchronousSocketChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IndexOutOfBoundsException * If the pre-conditions for the {@code offset} and {@code length} @@ -500,23 +490,24 @@ public abstract class AsynchronousSocketChannel * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future read(ByteBuffer[] dsts, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * Writes a sequence of bytes to this channel from the given buffer. * - *

    This method initiates the writing of a sequence of bytes to this channel - * from the given buffer, returning a {@code Future} representing the - * pending result of the operation. The {@code Future}'s {@link Future#get() - * get} method will return the number of bytes written. + *

    This method initiates an asynchronous write operation to write a + * sequence of bytes to this channel from the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the write + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes written. * *

    If a timeout is specified and the timeout elapses before the operation * completes then it completes with the exception {@link @@ -539,9 +530,7 @@ public abstract class AsynchronousSocketChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the {@code timeout} parameter is negative @@ -550,28 +539,28 @@ public abstract class AsynchronousSocketChannel * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * @throws WritePendingException {@inheritDoc} * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future write(ByteBuffer src, - A attachment, - CompletionHandler handler) + public final void write(ByteBuffer src, + A attachment, + CompletionHandler handler) { - return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); + write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** @@ -580,16 +569,16 @@ public abstract class AsynchronousSocketChannel * If this channel is not yet connected */ @Override - public final Future write(ByteBuffer src) { - return write(src, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future write(ByteBuffer src); /** * Writes a sequence of bytes to this channel from a subsequence of the given * buffers. This operation, sometimes called a gathering write, is * often useful when implementing network protocols that group data into * segments consisting of one or more fixed-length headers followed by a - * variable-length body. + * variable-length body. The {@code handler} parameter is a completion + * handler that is invoked when the write operation completes (or fails). + * The result passed to the completion handler is the number of bytes written. * *

    This method initiates a write of up to r bytes to this channel, * where r is the total number of bytes remaining in the specified @@ -616,10 +605,6 @@ public abstract class AsynchronousSocketChannel * remaining), exceeds this limit, then the I/O operation is performed with * the maximum number of buffers allowed by the operating system. * - *

    The return value from this method is a {@code Future} representing - * the pending result of the operation. The {@code Future}'s {@link - * Future#get() get} method will return the number of bytes written. - * *

    If a timeout is specified and the timeout elapses before the operation * completes then it completes with the exception {@link * InterruptedByTimeoutException}. Where a timeout occurs, and the @@ -644,9 +629,7 @@ public abstract class AsynchronousSocketChannel * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IndexOutOfBoundsException * If the pre-conditions for the {@code offset} and {@code length} @@ -658,13 +641,13 @@ public abstract class AsynchronousSocketChannel * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future write(ByteBuffer[] srcs, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); } diff --git a/src/share/classes/java/nio/channels/Channels.java b/src/share/classes/java/nio/channels/Channels.java index 4fdcef8abb0fdd8d23f34527761aa7fb6a803c8e..88f5e0eb8cff61f5486833ef79354d236483f10d 100644 --- a/src/share/classes/java/nio/channels/Channels.java +++ b/src/share/classes/java/nio/channels/Channels.java @@ -182,7 +182,6 @@ public final class Channels { } /** - * {@note new} * Constructs a stream that reads bytes from the given channel. * *

    The stream will not be buffered, and it will not support the {@link @@ -258,7 +257,6 @@ public final class Channels { } /** - * {@note new} * Constructs a stream that writes bytes to the given channel. * *

    The stream will not be buffered. The stream will be safe for access diff --git a/src/share/classes/java/nio/channels/CompletionHandler.java b/src/share/classes/java/nio/channels/CompletionHandler.java index c4d4add8ff9424b47d94499f58885f9868d251f8..43e5abeafb4888833b756fa09ea9c5e1893904e7 100644 --- a/src/share/classes/java/nio/channels/CompletionHandler.java +++ b/src/share/classes/java/nio/channels/CompletionHandler.java @@ -32,11 +32,9 @@ package java.nio.channels; * handler to be specified to consume the result of an asynchronous operation. * The {@link #completed completed} method is invoked when the I/O operation * completes successfully. The {@link #failed failed} method is invoked if the - * I/O operations fails. The {@link #cancelled cancelled} method is invoked when - * the I/O operation is cancelled by invoking the {@link - * java.util.concurrent.Future#cancel cancel} method. The implementations of - * these methods should complete in a timely manner so as to avoid keeping the - * invoking thread from dispatching to other completion handlers. + * I/O operations fails. The implementations of these methods should complete + * in a timely manner so as to avoid keeping the invoking thread from dispatching + * to other completion handlers. * * @param The result type of the I/O operation * @param The type of the object attached to the I/O operation @@ -65,13 +63,4 @@ public interface CompletionHandler { * The object attached to the I/O operation when it was initiated. */ void failed(Throwable exc, A attachment); - - /** - * Invoked when an operation is cancelled by invoking the {@link - * java.util.concurrent.Future#cancel cancel} method. - * - * @param attachment - * The object attached to the I/O operation when it was initiated. - */ - void cancelled(A attachment); } diff --git a/src/share/classes/java/nio/channels/FileChannel.java b/src/share/classes/java/nio/channels/FileChannel.java index ab780a520a9b3c75317bf7f13dd6d8acfffb6814..2a7713bd312a4c85229fc0cdbda4013658276fa7 100644 --- a/src/share/classes/java/nio/channels/FileChannel.java +++ b/src/share/classes/java/nio/channels/FileChannel.java @@ -39,8 +39,7 @@ import java.util.Collections; /** * A channel for reading, writing, mapping, and manipulating a file. * - *

    {@note revised} - * A file channel is a {@link SeekableByteChannel} that is connected to + *

    A file channel is a {@link SeekableByteChannel} that is connected to * a file. It has a current position within its file which can * be both {@link #position() queried} and {@link #position(long) * modified}. The file itself contains a variable-length sequence @@ -151,7 +150,6 @@ import java.util.Collections; * @author Mike McCloskey * @author JSR-51 Expert Group * @since 1.4 - * @updated 1.7 */ public abstract class FileChannel @@ -164,7 +162,6 @@ public abstract class FileChannel protected FileChannel() { } /** - * {@note new} * Opens or creates a file, returning a file channel to access the file. * *

    The {@code options} parameter determines how the file is opened. @@ -293,7 +290,6 @@ public abstract class FileChannel private static final FileAttribute[] NO_ATTRIBUTES = new FileAttribute[0]; /** - * {@note new} * Opens or creates a file, returning a file channel to access the file. * *

    An invocation of this method behaves in exactly the same way as the diff --git a/src/share/classes/java/nio/channels/FileLock.java b/src/share/classes/java/nio/channels/FileLock.java index b0ec37f1ba5a78f2c7a1b425fceb9d5686a6a232..8e1321144b5a6f2e60a2b4faced21c87c4173f82 100644 --- a/src/share/classes/java/nio/channels/FileLock.java +++ b/src/share/classes/java/nio/channels/FileLock.java @@ -114,7 +114,6 @@ import java.io.IOException; * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 - * @updated 1.7 */ public abstract class FileLock { @@ -161,7 +160,7 @@ public abstract class FileLock { } /** - * {@note new} Initializes a new instance of this class. + * Initializes a new instance of this class. * * @param channel * The channel upon whose file this lock is held @@ -199,7 +198,6 @@ public abstract class FileLock { } /** - * {@note revised} * Returns the file channel upon whose file this lock was acquired. * *

    This method has been superseded by the {@link #acquiredBy acquiredBy} @@ -213,7 +211,6 @@ public abstract class FileLock { } /** - * {@note new} * Returns the channel upon whose file this lock was acquired. * * @return The channel upon whose file this lock was acquired. diff --git a/src/share/classes/java/nio/channels/exceptions b/src/share/classes/java/nio/channels/exceptions index fed9f72ab2e068642926f5467b61dda42434a3eb..d78ea57738fcb9f4ed266bf409a61cc63e292b04 100644 --- a/src/share/classes/java/nio/channels/exceptions +++ b/src/share/classes/java/nio/channels/exceptions @@ -190,5 +190,5 @@ gen WritePendingException " gen ShutdownChannelGroupException " * Unchecked exception thrown when an attempt is made to construct a channel in * a group that is shutdown or the completion handler for an I/O operation - * cannot be invoked because the channel group is shutdown." \ + * cannot be invoked because the channel group has terminated." \ -3903801676350154157L diff --git a/src/share/classes/java/nio/channels/package-info.java b/src/share/classes/java/nio/channels/package-info.java index 36a408402607648d6f6c60c8ce12c2ee0ae3a47d..d5bf5110e317cb8c9b634c26dfad30b1512e69b1 100644 --- a/src/share/classes/java/nio/channels/package-info.java +++ b/src/share/classes/java/nio/channels/package-info.java @@ -285,7 +285,6 @@ * java.lang.NullPointerException NullPointerException} to be thrown. * * @since 1.4 - * @updated 1.7 * @author Mark Reinhold * @author JSR-51 Expert Group */ diff --git a/src/share/classes/java/nio/file/FileRef.java b/src/share/classes/java/nio/file/FileRef.java index 8a19ce285c2f10bced56b2c07869a392ee6b3376..c2bfee92916b65a6803bfc97d18e0b61ac4917f6 100644 --- a/src/share/classes/java/nio/file/FileRef.java +++ b/src/share/classes/java/nio/file/FileRef.java @@ -39,8 +39,6 @@ import java.io.IOException; * metadata or file attributes. * * @since 1.7 - * @see java.io.Inputs - * @see java.io.Outputs * @see java.nio.file.attribute.Attributes * @see java.io.File#toPath */ diff --git a/src/share/classes/java/util/Scanner.java b/src/share/classes/java/util/Scanner.java index c1032337bd2de111887443cdd082f51290de84ab..b7ec4b847d2682c6de8976bd5d72a270c2daed23 100644 --- a/src/share/classes/java/util/Scanner.java +++ b/src/share/classes/java/util/Scanner.java @@ -674,7 +674,6 @@ public final class Scanner implements Iterator { } /** - * {@note new} * Constructs a new Scanner that produces values scanned * from the specified file. Bytes from the file are converted into * characters using the underlying platform's @@ -694,7 +693,6 @@ public final class Scanner implements Iterator { } /** - * {@note new} * Constructs a new Scanner that produces values scanned * from the specified file. Bytes from the file are converted into * characters using the specified charset. diff --git a/src/share/classes/sun/nio/ch/AbstractFuture.java b/src/share/classes/sun/nio/ch/AbstractFuture.java deleted file mode 100644 index f79dc7abbbfa2ea658c298d4bca20ba66e4fecb2..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/AbstractFuture.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package sun.nio.ch; - -import java.nio.channels.AsynchronousChannel; -import java.util.concurrent.Future; - -/** - * Base implementation of Future used for asynchronous I/O - */ - -abstract class AbstractFuture - implements Future -{ - private final AsynchronousChannel channel; - private final A attachment; - - protected AbstractFuture(AsynchronousChannel channel, A attachment) { - this.channel = channel; - this.attachment = attachment; - } - - final AsynchronousChannel channel() { - return channel; - } - - final A attachment() { - return attachment; - } - - /** - * Returns the result of the operation if it has completed successfully. - */ - abstract V value(); - - /** - * Returns the exception if the operation has failed. - */ - abstract Throwable exception(); -} diff --git a/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java b/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java index 14e33ffe9d138f14c2217578d2facc0e3bae3762..5bfc94e36c5d9c7f3df033355621485fa1d47c8d 100644 --- a/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java +++ b/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java @@ -32,8 +32,8 @@ import java.io.IOException; import java.io.FileDescriptor; import java.util.Queue; import java.util.concurrent.*; -import java.util.concurrent.locks.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicBoolean; import java.security.PrivilegedAction; import java.security.AccessController; import java.security.AccessControlContext; @@ -65,11 +65,8 @@ abstract class AsynchronousChannelGroupImpl private final Queue taskQueue; // group shutdown - // shutdownLock is RW lock so as to allow for concurrent queuing of tasks - // when using a fixed thread pool. - private final ReadWriteLock shutdownLock = new ReentrantReadWriteLock(); + private final AtomicBoolean shutdown = new AtomicBoolean(); private final Object shutdownNowLock = new Object(); - private volatile boolean shutdown; private volatile boolean terminateInitiated; AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider, @@ -214,7 +211,7 @@ abstract class AsynchronousChannelGroupImpl @Override public final boolean isShutdown() { - return shutdown; + return shutdown.get(); } @Override @@ -260,17 +257,10 @@ abstract class AsynchronousChannelGroupImpl @Override public final void shutdown() { - shutdownLock.writeLock().lock(); - try { - if (shutdown) { - // already shutdown - return; - } - shutdown = true; - } finally { - shutdownLock.writeLock().unlock(); + if (shutdown.getAndSet(true)) { + // already shutdown + return; } - // if there are channels in the group then shutdown will continue // when the last channel is closed if (!isEmpty()) { @@ -289,12 +279,7 @@ abstract class AsynchronousChannelGroupImpl @Override public final void shutdownNow() throws IOException { - shutdownLock.writeLock().lock(); - try { - shutdown = true; - } finally { - shutdownLock.writeLock().unlock(); - } + shutdown.set(true); synchronized (shutdownNowLock) { if (!terminateInitiated) { terminateInitiated = true; @@ -305,6 +290,18 @@ abstract class AsynchronousChannelGroupImpl } } + /** + * For use by AsynchronousFileChannel to release resources without shutting + * down the thread pool. + */ + final void detachFromThreadPool() { + if (shutdown.getAndSet(true)) + throw new AssertionError("Already shutdown"); + if (!isEmpty()) + throw new AssertionError("Group not empty"); + shutdownHandlerTasks(); + } + @Override public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException diff --git a/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java b/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java index 180238d841357a42a1cdb6bd3b5cd5d510eb5fe5..8757b999c9d60252585c543083c8ad3ae1819c3e 100644 --- a/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java +++ b/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java @@ -25,8 +25,10 @@ package sun.nio.ch; +import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import java.util.concurrent.locks.*; import java.io.FileDescriptor; import java.io.IOException; @@ -101,6 +103,33 @@ abstract class AsynchronousFileChannelImpl // -- file locking -- + abstract Future implLock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler); + + @Override + public final Future lock(long position, + long size, + boolean shared) + + { + return implLock(position, size, shared, null, null); + } + + @Override + public final void lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implLock(position, size, shared, attachment, handler); + } + private volatile FileLockTable fileLockTable; final void ensureFileLockTableInitialized() throws IOException { @@ -175,4 +204,50 @@ abstract class AsynchronousFileChannelImpl end(); } } + + + // -- reading and writing -- + + abstract Future implRead(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler); + + @Override + public final Future read(ByteBuffer dst, long position) { + return implRead(dst, position, null, null); + } + + @Override + public final void read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implRead(dst, position, attachment, handler); + } + + abstract Future implWrite(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler); + + + @Override + public final Future write(ByteBuffer src, long position) { + return implWrite(src, position, null, null); + } + + @Override + public final void write(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implWrite(src, position, attachment, handler); + } } diff --git a/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java index 492319301590ea115c0540502ea56d5e4888b97d..47bf820d6beb2ea1d34217a0d7b9397f3805a77f 100644 --- a/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java @@ -35,6 +35,7 @@ import java.io.IOException; import java.util.Set; import java.util.HashSet; import java.util.Collections; +import java.util.concurrent.Future; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import sun.net.NetHooks; @@ -108,6 +109,29 @@ abstract class AsynchronousServerSocketChannelImpl implClose(); } + /** + * Invoked by accept to accept connection + */ + abstract Future + implAccept(Object attachment, + CompletionHandler handler); + + + @Override + public final Future accept() { + return implAccept(null, null); + } + + @Override + @SuppressWarnings("unchecked") + public final void accept(A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implAccept(attachment, (CompletionHandler)handler); + } + final boolean isAcceptKilled() { return acceptKilled; } diff --git a/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java index 84b81a0c8b0bf93f0b0e13826b0259f9e5f3791a..d378320716e9af0f4e3060b152935a3b66d3598b 100644 --- a/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -183,29 +183,54 @@ abstract class AsynchronousSocketChannelImpl killWriting(); } + /** + * Invoked by connect to initiate the connect operation. + */ + abstract Future implConnect(SocketAddress remote, + A attachment, + CompletionHandler handler); + + @Override + public final Future connect(SocketAddress remote) { + return implConnect(remote, null, null); + } + + @Override + public final void connect(SocketAddress remote, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implConnect(remote, attachment, handler); + } + /** * Invoked by read to initiate the I/O operation. */ - abstract Future readImpl(ByteBuffer[] dsts, - boolean isScatteringRead, + abstract Future implRead(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); @SuppressWarnings("unchecked") - private Future read(ByteBuffer[] dsts, - boolean isScatteringRead, + private Future read(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, - A attachment, + A att, CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(e); + Invoker.invoke(this, handler, att, null, e); + return null; } if (remoteAddress == null) @@ -213,13 +238,13 @@ abstract class AsynchronousSocketChannelImpl if (timeout < 0L) throw new IllegalArgumentException("Negative timeout"); - boolean hasSpaceToRead = isScatteringRead || dsts[0].hasRemaining(); + boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining(); boolean shutdown = false; // check and update state synchronized (readLock) { if (readKilled) - throw new RuntimeException("Reading not allowed due to timeout or cancellation"); + throw new IllegalStateException("Reading not allowed due to timeout or cancellation"); if (reading) throw new ReadPendingException(); if (readShutdown) { @@ -234,44 +259,53 @@ abstract class AsynchronousSocketChannelImpl // immediately complete with -1 if shutdown for read // immediately complete with 0 if no space remaining if (shutdown || !hasSpaceToRead) { - CompletedFuture result; + Number result; if (isScatteringRead) { - Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); - result = (CompletedFuture)CompletedFuture.withResult(this, value, attachment); + result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); } else { - int value = (shutdown) ? -1 : 0; - result = (CompletedFuture)CompletedFuture.withResult(this, value, attachment); + result = (shutdown) ? -1 : 0; } - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult((V)result); + Invoker.invoke(this, handler, att, (V)result, null); + return null; } - return readImpl(dsts, isScatteringRead, timeout, unit, attachment, handler); + return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler); } @Override - public final Future read(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final Future read(ByteBuffer dst) { + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null); + } + + @Override + public final void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { + if (handler == null) + throw new NullPointerException("'handler' is null"); if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); - ByteBuffer[] bufs = new ByteBuffer[1]; - bufs[0] = dst; - return read(bufs, false, timeout, unit, attachment, handler); + read(false, dst, null, timeout, unit, attachment, handler); } @Override - public final Future read(ByteBuffer[] dsts, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { + if (handler == null) + throw new NullPointerException("'handler' is null"); if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) throw new IndexOutOfBoundsException(); ByteBuffer[] bufs = Util.subsequence(dsts, offset, length); @@ -279,39 +313,41 @@ abstract class AsynchronousSocketChannelImpl if (bufs[i].isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); } - return read(bufs, true, timeout, unit, attachment, handler); + read(true, null, bufs, timeout, unit, attachment, handler); } /** * Invoked by write to initiate the I/O operation. */ - abstract Future writeImpl(ByteBuffer[] srcs, - boolean isGatheringWrite, + abstract Future implWrite(boolean isGatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); @SuppressWarnings("unchecked") - private Future write(ByteBuffer[] srcs, - boolean isGatheringWrite, + private Future write(boolean isGatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, - A attachment, + A att, CompletionHandler handler) { - boolean hasDataToWrite = isGatheringWrite || srcs[0].hasRemaining(); + boolean hasDataToWrite = isGatheringWrite || src.hasRemaining(); boolean closed = false; if (isOpen()) { if (remoteAddress == null) throw new NotYetConnectedException(); - if (timeout < 0L) + if (timeout < 0L) throw new IllegalArgumentException("Negative timeout"); // check and update state synchronized (writeLock) { if (writeKilled) - throw new RuntimeException("Writing not allowed due to timeout or cancellation"); + throw new IllegalStateException("Writing not allowed due to timeout or cancellation"); if (writing) throw new WritePendingException(); if (writeShutdown) { @@ -327,52 +363,57 @@ abstract class AsynchronousSocketChannelImpl // channel is closed or shutdown for write if (closed) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(e); + Invoker.invoke(this, handler, att, null, e); + return null; } // nothing to write so complete immediately if (!hasDataToWrite) { - CompletedFuture result; - if (isGatheringWrite) { - result = (CompletedFuture)CompletedFuture.withResult(this, 0L, attachment); - } else { - result = (CompletedFuture)CompletedFuture.withResult(this, 0, attachment); - } - Invoker.invoke(handler, result); - return result; + Number result = (isGatheringWrite) ? (Number)0L : (Number)0; + if (handler == null) + return CompletedFuture.withResult((V)result); + Invoker.invoke(this, handler, att, (V)result, null); + return null; } - return writeImpl(srcs, isGatheringWrite, timeout, unit, attachment, handler); + return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler); } @Override - public final Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final Future write(ByteBuffer src) { + return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null); + } + + @Override + public final void write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { - ByteBuffer[] bufs = new ByteBuffer[1]; - bufs[0] = src; - return write(bufs, false, timeout, unit, attachment, handler); + if (handler == null) + throw new NullPointerException("'handler' is null"); + write(false, src, null, timeout, unit, attachment, handler); } @Override - public final Future write(ByteBuffer[] srcs, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final void write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { + if (handler == null) + throw new NullPointerException("'handler' is null"); if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) throw new IndexOutOfBoundsException(); srcs = Util.subsequence(srcs, offset, length); - return write(srcs, true, timeout, unit, attachment, handler); + write(true, null, srcs, timeout, unit, attachment, handler); } @Override @@ -461,7 +502,6 @@ abstract class AsynchronousSocketChannelImpl } @Override - @SuppressWarnings("unchecked") public final SocketAddress getRemoteAddress() throws IOException { if (!isOpen()) throw new ClosedChannelException(); diff --git a/src/share/classes/sun/nio/ch/CompletedFuture.java b/src/share/classes/sun/nio/ch/CompletedFuture.java index 221b9f8f5f71b8caae539a2f8b645b31050e5ec7..c3152db6097743b1f584dd78e924bc6916149c01 100644 --- a/src/share/classes/sun/nio/ch/CompletedFuture.java +++ b/src/share/classes/sun/nio/ch/CompletedFuture.java @@ -25,7 +25,7 @@ package sun.nio.ch; -import java.nio.channels.AsynchronousChannel; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.ExecutionException; import java.io.IOException; @@ -35,39 +35,35 @@ import java.io.IOException; * completed. */ -final class CompletedFuture - extends AbstractFuture -{ +final class CompletedFuture implements Future { private final V result; private final Throwable exc; - private CompletedFuture(AsynchronousChannel channel, - V result, - Throwable exc, - A attachment) - { - super(channel, attachment); + private CompletedFuture(V result, Throwable exc) { this.result = result; this.exc = exc; } @SuppressWarnings("unchecked") - static CompletedFuture withResult(AsynchronousChannel channel, - V result, - A attachment) - { - return new CompletedFuture(channel, result, null, attachment); + static CompletedFuture withResult(V result) { + return new CompletedFuture(result, null); } @SuppressWarnings("unchecked") - static CompletedFuture withFailure(AsynchronousChannel channel, - Throwable exc, - A attachment) - { + static CompletedFuture withFailure(Throwable exc) { // exception must be IOException or SecurityException if (!(exc instanceof IOException) && !(exc instanceof SecurityException)) exc = new IOException(exc); - return new CompletedFuture(channel, null, exc, attachment); + return new CompletedFuture(null, exc); + } + + @SuppressWarnings("unchecked") + static CompletedFuture withResult(V result, Throwable exc) { + if (exc == null) { + return withResult(result); + } else { + return withFailure(exc); + } } @Override @@ -100,14 +96,4 @@ final class CompletedFuture public boolean cancel(boolean mayInterruptIfRunning) { return false; } - - @Override - Throwable exception() { - return exc; - } - - @Override - V value() { - return result; - } } diff --git a/src/share/classes/sun/nio/ch/Invoker.java b/src/share/classes/sun/nio/ch/Invoker.java index 182f7989a469e14a1981656638cea716128632a2..c4fcfb980413bfae7f3cea22b9812d3118a9730d 100644 --- a/src/share/classes/sun/nio/ch/Invoker.java +++ b/src/share/classes/sun/nio/ch/Invoker.java @@ -117,33 +117,32 @@ class Invoker { * Invoke handler without checking the thread identity or number of handlers * on the thread stack. */ - @SuppressWarnings("unchecked") static void invokeUnchecked(CompletionHandler handler, - AbstractFuture result) + A attachment, + V value, + Throwable exc) { - if (handler != null && !result.isCancelled()) { - Throwable exc = result.exception(); - if (exc == null) { - handler.completed(result.value(), result.attachment()); - } else { - handler.failed(exc, result.attachment()); - } - - // clear interrupt - Thread.interrupted(); + if (exc == null) { + handler.completed(value, attachment); + } else { + handler.failed(exc, attachment); } - } + // clear interrupt + Thread.interrupted(); + } /** - * Invoke handler after incrementing the invoke count. + * Invoke handler assuming thread identity already checked */ static void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, CompletionHandler handler, - AbstractFuture result) + A attachment, + V result, + Throwable exc) { myGroupAndInvokeCount.incrementInvokeCount(); - invokeUnchecked(handler, result); + Invoker.invokeUnchecked(handler, attachment, result, exc); } /** @@ -151,64 +150,64 @@ class Invoker { * thread pool then the handler is invoked directly, otherwise it is * invoked indirectly. */ - static void invoke(CompletionHandler handler, - AbstractFuture result) + static void invoke(AsynchronousChannel channel, + CompletionHandler handler, + A attachment, + V result, + Throwable exc) { - if (handler != null) { - boolean invokeDirect = false; - boolean identityOkay = false; - GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); - if (thisGroupAndInvokeCount != null) { - AsynchronousChannel channel = result.channel(); - if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) - identityOkay = true; - if (identityOkay && - (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) - { - // group match - invokeDirect = true; - } + boolean invokeDirect = false; + boolean identityOkay = false; + GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); + if (thisGroupAndInvokeCount != null) { + if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) + identityOkay = true; + if (identityOkay && + (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) + { + // group match + invokeDirect = true; } - if (invokeDirect) { - thisGroupAndInvokeCount.incrementInvokeCount(); - invokeUnchecked(handler, result); - } else { - try { - invokeIndirectly(handler, result); - } catch (RejectedExecutionException ree) { - // channel group shutdown; fallback to invoking directly - // if the current thread has the right identity. - if (identityOkay) { - invokeUnchecked(handler, result); - } else { - throw new ShutdownChannelGroupException(); - } + } + if (invokeDirect) { + invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc); + } else { + try { + invokeIndirectly(channel, handler, attachment, result, exc); + } catch (RejectedExecutionException ree) { + // channel group shutdown; fallback to invoking directly + // if the current thread has the right identity. + if (identityOkay) { + invokeDirect(thisGroupAndInvokeCount, + handler, attachment, result, exc); + } else { + throw new ShutdownChannelGroupException(); } } } } /** - * Invokes the handler "indirectly" in the channel group's thread pool. + * Invokes the handler indirectly via the channel group's thread pool. */ - static void invokeIndirectly(final CompletionHandler handler, - final AbstractFuture result) + static void invokeIndirectly(AsynchronousChannel channel, + final CompletionHandler handler, + final A attachment, + final V result, + final Throwable exc) { - if (handler != null) { - AsynchronousChannel channel = result.channel(); - try { - ((Groupable)channel).group().executeOnPooledThread(new Runnable() { - public void run() { - GroupAndInvokeCount thisGroupAndInvokeCount = - myGroupAndInvokeCount.get(); - if (thisGroupAndInvokeCount != null) - thisGroupAndInvokeCount.setInvokeCount(1); - invokeUnchecked(handler, result); - } - }); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + try { + ((Groupable)channel).group().executeOnPooledThread(new Runnable() { + public void run() { + GroupAndInvokeCount thisGroupAndInvokeCount = + myGroupAndInvokeCount.get(); + if (thisGroupAndInvokeCount != null) + thisGroupAndInvokeCount.setInvokeCount(1); + invokeUnchecked(handler, attachment, result, exc); + } + }); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); } } @@ -216,19 +215,19 @@ class Invoker { * Invokes the handler "indirectly" in the given Executor */ static void invokeIndirectly(final CompletionHandler handler, - final AbstractFuture result, + final A attachment, + final V value, + final Throwable exc, Executor executor) { - if (handler != null) { - try { - executor.execute(new Runnable() { - public void run() { - invokeUnchecked(handler, result); - } - }); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + try { + executor.execute(new Runnable() { + public void run() { + invokeUnchecked(handler, attachment, value, exc); + } + }); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); } } @@ -258,4 +257,52 @@ class Invoker { throw new ShutdownChannelGroupException(); } } + + /** + * Invoke handler with completed result. This method does not check the + * thread identity or the number of handlers on the thread stack. + */ + static void invokeUnchecked(PendingFuture future) { + assert future.isDone(); + CompletionHandler handler = future.handler(); + if (handler != null) { + invokeUnchecked(handler, + future.attachment(), + future.value(), + future.exception()); + } + } + + /** + * Invoke handler with completed result. If the current thread is in the + * channel group's thread pool then the handler is invoked directly, + * otherwise it is invoked indirectly. + */ + static void invoke(PendingFuture future) { + assert future.isDone(); + CompletionHandler handler = future.handler(); + if (handler != null) { + invoke(future.channel(), + handler, + future.attachment(), + future.value(), + future.exception()); + } + } + + /** + * Invoke handler with completed result. The handler is invoked indirectly, + * via the channel group's thread pool. + */ + static void invokeIndirectly(PendingFuture future) { + assert future.isDone(); + CompletionHandler handler = future.handler(); + if (handler != null) { + invokeIndirectly(future.channel(), + handler, + future.attachment(), + future.value(), + future.exception()); + } + } } diff --git a/src/share/classes/sun/nio/ch/PendingFuture.java b/src/share/classes/sun/nio/ch/PendingFuture.java index d88cf233a821a03e3174fe3f2b6288b1029a1e84..3b1899a62da9eb13e6f52ea75749551355b8dc99 100644 --- a/src/share/classes/sun/nio/ch/PendingFuture.java +++ b/src/share/classes/sun/nio/ch/PendingFuture.java @@ -34,13 +34,13 @@ import java.io.IOException; * attachment of an additional arbitrary context object and a timer task. */ -final class PendingFuture - extends AbstractFuture -{ +final class PendingFuture implements Future { private static final CancellationException CANCELLED = new CancellationException(); + private final AsynchronousChannel channel; private final CompletionHandler handler; + private final A attachment; // true if result (or exception) is available private volatile boolean haveResult; @@ -56,14 +56,14 @@ final class PendingFuture // optional context object private volatile Object context; - PendingFuture(AsynchronousChannel channel, CompletionHandler handler, A attachment, Object context) { - super(channel, attachment); + this.channel = channel; this.handler = handler; + this.attachment = attachment; this.context = context; } @@ -71,14 +71,31 @@ final class PendingFuture CompletionHandler handler, A attachment) { - super(channel, attachment); + this.channel = channel; this.handler = handler; + this.attachment = attachment; + } + + PendingFuture(AsynchronousChannel channel) { + this(channel, null, null); + } + + PendingFuture(AsynchronousChannel channel, Object context) { + this(channel, null, null, context); + } + + AsynchronousChannel channel() { + return channel; } CompletionHandler handler() { return handler; } + A attachment() { + return attachment; + } + void setContext(Object context) { this.context = context; } @@ -113,36 +130,45 @@ final class PendingFuture /** * Sets the result, or a no-op if the result or exception is already set. */ - boolean setResult(V res) { + void setResult(V res) { synchronized (this) { if (haveResult) - return false; + return; result = res; haveResult = true; if (timeoutTask != null) timeoutTask.cancel(false); if (latch != null) latch.countDown(); - return true; } } /** * Sets the result, or a no-op if the result or exception is already set. */ - boolean setFailure(Throwable x) { + void setFailure(Throwable x) { if (!(x instanceof IOException) && !(x instanceof SecurityException)) x = new IOException(x); synchronized (this) { if (haveResult) - return false; + return; exc = x; haveResult = true; if (timeoutTask != null) timeoutTask.cancel(false); if (latch != null) latch.countDown(); - return true; + } + } + + /** + * Sets the result + */ + void setResult(V res, Throwable x) { + if (x == null) { + setResult(res); + } else { + setFailure(x); } } @@ -178,12 +204,10 @@ final class PendingFuture return result; } - @Override Throwable exception() { return (exc != CANCELLED) ? exc : null; } - @Override V value() { return result; } @@ -204,33 +228,6 @@ final class PendingFuture if (haveResult) return false; // already completed - // A shutdown of the channel group will close all channels and - // shutdown the executor. To ensure that the completion handler - // is executed we queue the task while holding the lock. - if (handler != null) { - prepareForWait(); - Runnable cancelTask = new Runnable() { - public void run() { - while (!haveResult) { - try { - latch.await(); - } catch (InterruptedException ignore) { } - } - handler.cancelled(attachment()); - } - }; - AsynchronousChannel ch = channel(); - if (ch instanceof Groupable) { - ((Groupable)ch).group().executeOnPooledThread(cancelTask); - } else { - if (ch instanceof AsynchronousFileChannelImpl) { - ((AsynchronousFileChannelImpl)ch).executor().execute(cancelTask); - } else { - throw new AssertionError("Should not get here"); - } - } - } - // notify channel if (channel() instanceof Cancellable) ((Cancellable)channel()).onCancel(this); @@ -249,7 +246,7 @@ final class PendingFuture } catch (IOException ignore) { } } - // release waiters (this also releases the invoker) + // release waiters if (latch != null) latch.countDown(); return true; diff --git a/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java b/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java index 47c3b2abd29059e116ea86b5e28774228a35e6e0..e504da338a2722c6b2e2e0c445f05cf7e8938bce 100644 --- a/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java +++ b/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java @@ -317,51 +317,71 @@ class SimpleAsynchronousDatagramChannelImpl return new WrappedMembershipKey(this, key); } - @Override - public Future send(ByteBuffer src, - SocketAddress target, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + private Future implSend(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler) { - if (timeout < 0L) - throw new IllegalArgumentException("Negative timeout"); - if (unit == null) - throw new NullPointerException(); - - CompletedFuture result; + int n = 0; + Throwable exc = null; try { - int n = dc.send(src, target); - result = CompletedFuture.withResult(this, n, attachment); + n = dc.send(src, target); } catch (IOException ioe) { - result = CompletedFuture.withFailure(this, ioe, attachment); + exc = ioe; } - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(n, exc); + Invoker.invoke(this, handler, attachment, n, exc); + return null; + } + + @Override + public Future send(ByteBuffer src, SocketAddress target) { + return implSend(src, target, null, null); } @Override - public Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public void send(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler) { - if (timeout < 0L) - throw new IllegalArgumentException("Negative timeout"); - if (unit == null) - throw new NullPointerException(); + if (handler == null) + throw new NullPointerException("'handler' is null"); + implSend(src, target, attachment, handler); + } - CompletedFuture result; + private Future implWrite(ByteBuffer src, + A attachment, + CompletionHandler handler) + { + int n = 0; + Throwable exc = null; try { - int n = dc.write(src); - result = CompletedFuture.withResult(this, n, attachment); + n = dc.write(src); } catch (IOException ioe) { - result = CompletedFuture.withFailure(this, ioe, attachment); + exc = ioe; } - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(n, exc); + Invoker.invoke(this, handler, attachment, n, exc); + return null; + + } + + @Override + public Future write(ByteBuffer src) { + return implWrite(src, null, null); + } + + @Override + public void write(ByteBuffer src, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implWrite(src, attachment, handler); } /** @@ -390,12 +410,11 @@ class SimpleAsynchronousDatagramChannelImpl } } - @Override - public Future receive(final ByteBuffer dst, - final long timeout, - final TimeUnit unit, - A attachment, - final CompletionHandler handler) + private Future implReceive(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler handler) { if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); @@ -406,10 +425,11 @@ class SimpleAsynchronousDatagramChannelImpl // complete immediately if channel closed if (!isOpen()) { - CompletedFuture result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } final AccessControlContext acc = (System.getSecurityManager() == null) ? @@ -471,7 +491,7 @@ class SimpleAsynchronousDatagramChannelImpl x = new AsynchronousCloseException(); result.setFailure(x); } - Invoker.invokeUnchecked(handler, result); + Invoker.invokeUnchecked(result); } }; try { @@ -483,11 +503,27 @@ class SimpleAsynchronousDatagramChannelImpl } @Override - public Future read(final ByteBuffer dst, - final long timeout, - final TimeUnit unit, - A attachment, - final CompletionHandler handler) + public Future receive(ByteBuffer dst) { + return implReceive(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + @Override + public void receive(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implReceive(dst, timeout, unit, attachment, handler); + } + + private Future implRead(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler handler) { if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); @@ -495,18 +531,20 @@ class SimpleAsynchronousDatagramChannelImpl throw new IllegalArgumentException("Negative timeout"); if (unit == null) throw new NullPointerException(); - // another thread may disconnect before read is initiated - if (!dc.isConnected()) - throw new NotYetConnectedException(); // complete immediately if channel closed if (!isOpen()) { - CompletedFuture result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } + // another thread may disconnect before read is initiated + if (!dc.isConnected()) + throw new NotYetConnectedException(); + final PendingFuture result = new PendingFuture(this, handler, attachment); Runnable task = new Runnable() { @@ -563,7 +601,7 @@ class SimpleAsynchronousDatagramChannelImpl x = new AsynchronousCloseException(); result.setFailure(x); } - Invoker.invokeUnchecked(handler, result); + Invoker.invokeUnchecked(result); } }; try { @@ -574,6 +612,23 @@ class SimpleAsynchronousDatagramChannelImpl return result; } + @Override + public Future read(ByteBuffer dst) { + return implRead(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + @Override + public void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implRead(dst, timeout, unit, attachment, handler); + } + @Override public AsynchronousDatagramChannel bind(SocketAddress local) throws IOException diff --git a/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java b/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java index fb82f330be457dc0030b7b4b0cd984f21d3af38e..ef9ff8fec4198449bbbdbe7054e5ab6129d47d77 100644 --- a/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java +++ b/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java @@ -50,9 +50,6 @@ public class SimpleAsynchronousFileChannelImpl // Used to make native read and write calls private static final FileDispatcher nd = new FileDispatcherImpl(); - // indicates if the associated thread pool is the default thread pool - private final boolean isDefaultExecutor; - // Thread-safe set of IDs of native threads, for signalling private final NativeThreadSet threads = new NativeThreadSet(2); @@ -60,11 +57,9 @@ public class SimpleAsynchronousFileChannelImpl SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj, boolean reading, boolean writing, - ExecutorService executor, - boolean isDefaultexecutor) + ExecutorService executor) { super(fdObj, reading, writing, executor); - this.isDefaultExecutor = isDefaultexecutor; } public static AsynchronousFileChannel open(FileDescriptor fdo, @@ -73,17 +68,9 @@ public class SimpleAsynchronousFileChannelImpl ThreadPool pool) { // Executor is either default or based on pool parameters - ExecutorService executor; - boolean isDefaultexecutor; - if (pool == null) { - executor = DefaultExecutorHolder.defaultExecutor; - isDefaultexecutor = true; - } else { - executor = pool.executor(); - isDefaultexecutor = false; - } - return new SimpleAsynchronousFileChannelImpl(fdo, - reading, writing, executor, isDefaultexecutor); + ExecutorService executor = (pool == null) ? + DefaultExecutorHolder.defaultExecutor : pool.executor(); + return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor); } @Override @@ -114,16 +101,6 @@ public class SimpleAsynchronousFileChannelImpl // close file nd.close(fdObj); - - // shutdown executor if specific to this channel - if (!isDefaultExecutor) { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - executor.shutdown(); - return null; - } - }); - } } @Override @@ -194,11 +171,11 @@ public class SimpleAsynchronousFileChannelImpl } @Override - public Future lock(final long position, - final long size, - final boolean shared, - A attachment, - final CompletionHandler handler) + Future implLock(final long position, + final long size, + final boolean shared, + final A attachment, + final CompletionHandler handler) { if (shared && !reading) throw new NonReadableChannelException(); @@ -208,16 +185,19 @@ public class SimpleAsynchronousFileChannelImpl // add to lock table final FileLockImpl fli = addToFileLockTable(position, size, shared); if (fli == null) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invokeIndirectly(handler, result, executor); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invokeIndirectly(handler, attachment, null, exc, executor); + return null; } - final PendingFuture result = - new PendingFuture(this, handler, attachment); + final PendingFuture result = (handler == null) ? + new PendingFuture(this) : null; Runnable task = new Runnable() { public void run() { + Throwable exc = null; + int ti = threads.add(); try { int n; @@ -226,31 +206,36 @@ public class SimpleAsynchronousFileChannelImpl do { n = nd.lock(fdObj, true, position, size, shared); } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); - if (n == FileDispatcher.LOCKED && isOpen()) { - result.setResult(fli); - } else { + if (n != FileDispatcher.LOCKED || !isOpen()) { throw new AsynchronousCloseException(); } } catch (IOException x) { removeFromFileLockTable(fli); if (!isOpen()) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { end(); } } finally { threads.remove(ti); } - Invoker.invokeUnchecked(handler, result); + if (handler == null) { + result.setResult(fli, exc); + } else { + Invoker.invokeUnchecked(handler, attachment, fli, exc); + } } }; + boolean executed = false; try { executor.execute(task); - } catch (RejectedExecutionException ree) { - // rollback - removeFromFileLockTable(fli); - throw new ShutdownChannelGroupException(); + executed = true; + } finally { + if (!executed) { + // rollback + removeFromFileLockTable(fli); + } } return result; } @@ -301,10 +286,10 @@ public class SimpleAsynchronousFileChannelImpl } @Override - public Future read(final ByteBuffer dst, - final long position, - A attachment, - final CompletionHandler handler) + Future implRead(final ByteBuffer dst, + final long position, + final A attachment, + final CompletionHandler handler) { if (position < 0) throw new IllegalArgumentException("Negative position"); @@ -315,55 +300,52 @@ public class SimpleAsynchronousFileChannelImpl // complete immediately if channel closed or no space remaining if (!isOpen() || (dst.remaining() == 0)) { - CompletedFuture result; - if (isOpen()) { - result = CompletedFuture.withResult(this, 0, attachment); - } else { - result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - } - Invoker.invokeIndirectly(handler, result, executor); - return result; + Throwable exc = (isOpen()) ? null : new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withResult(0, exc); + Invoker.invokeIndirectly(handler, attachment, 0, exc, executor); + return null; } - final PendingFuture result = - new PendingFuture(this, handler, attachment); + final PendingFuture result = (handler == null) ? + new PendingFuture(this) : null; Runnable task = new Runnable() { public void run() { + int n = 0; + Throwable exc = null; + int ti = threads.add(); try { begin(); - int n; do { n = IOUtil.read(fdObj, dst, position, nd, null); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n < 0 && !isOpen()) throw new AsynchronousCloseException(); - result.setResult(n); } catch (IOException x) { if (!isOpen()) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { end(); threads.remove(ti); } - Invoker.invokeUnchecked(handler, result); + if (handler == null) { + result.setResult(n, exc); + } else { + Invoker.invokeUnchecked(handler, attachment, n, exc); + } } }; - try { - executor.execute(task); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + executor.execute(task); return result; } @Override - public Future write(final ByteBuffer src, - final long position, - A attachment, - final CompletionHandler handler) + Future implWrite(final ByteBuffer src, + final long position, + final A attachment, + final CompletionHandler handler) { if (position < 0) throw new IllegalArgumentException("Negative position"); @@ -372,47 +354,44 @@ public class SimpleAsynchronousFileChannelImpl // complete immediately if channel is closed or no bytes remaining if (!isOpen() || (src.remaining() == 0)) { - CompletedFuture result; - if (isOpen()) { - result = CompletedFuture.withResult(this, 0, attachment); - } else { - result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - } - Invoker.invokeIndirectly(handler, result, executor); - return result; + Throwable exc = (isOpen()) ? null : new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withResult(0, exc); + Invoker.invokeIndirectly(handler, attachment, 0, exc, executor); + return null; } - final PendingFuture result = - new PendingFuture(this, handler, attachment); + final PendingFuture result = (handler == null) ? + new PendingFuture(this) : null; Runnable task = new Runnable() { public void run() { + int n = 0; + Throwable exc = null; + int ti = threads.add(); try { begin(); - int n; do { n = IOUtil.write(fdObj, src, position, nd, null); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n < 0 && !isOpen()) throw new AsynchronousCloseException(); - result.setResult(n); } catch (IOException x) { if (!isOpen()) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { end(); threads.remove(ti); } - Invoker.invokeUnchecked(handler, result); + if (handler == null) { + result.setResult(n, exc); + } else { + Invoker.invokeUnchecked(handler, attachment, n, exc); + } } }; - try { - executor.execute(task); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + executor.execute(task); return result; } } diff --git a/src/share/classes/sun/nio/cs/ext/ISO2022.java b/src/share/classes/sun/nio/cs/ext/ISO2022.java index 242a841d46fd7a76114b84b5173b20dad448c8b6..036dc04299dbb312023872eb8099548728eb877e 100644 --- a/src/share/classes/sun/nio/cs/ext/ISO2022.java +++ b/src/share/classes/sun/nio/cs/ext/ISO2022.java @@ -388,9 +388,9 @@ abstract class ISO2022 protected static class Encoder extends CharsetEncoder { private final Surrogate.Parser sgp = new Surrogate.Parser(); - private final byte SS2 = (byte)0x8e; - private final byte PLANE2 = (byte)0xA2; - private final byte PLANE3 = (byte)0xA3; + public static final byte SS2 = (byte)0x8e; + public static final byte PLANE2 = (byte)0xA2; + public static final byte PLANE3 = (byte)0xA3; private final byte MSB = (byte)0x80; protected final byte maximumDesignatorLength = 4; diff --git a/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java b/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java index e5b5d7195152650457eeb5888d24e55569c16042..72e11ff1a76deaaed8475a62d266ae6e575382d5 100644 --- a/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java +++ b/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java @@ -76,6 +76,15 @@ public class ISO2022_CN_CNS extends ISO2022 implements HistoricallyNamedCharset } catch (Exception e) { } } + private byte[] bb = new byte[4]; + public boolean canEncode(char c) { + int n = 0; + return (c <= '\u007f' || + (n = ((EUC_TW.Encoder)ISOEncoder).toEUC(c, bb)) == 2 || + (n == 4 && bb[0] == SS2 && + (bb[1] == PLANE2 || bb[1] == PLANE3))); + } + /* * Since ISO2022-CN-CNS possesses a CharsetEncoder * without the corresponding CharsetDecoder half the diff --git a/src/share/classes/sun/security/jgss/SunProvider.java b/src/share/classes/sun/security/jgss/SunProvider.java index 362bec5936db9f2d7ad720ecb3806cb5d51e814d..26039b9db1dc3e4e565f3d683c53ad2ff5eb304c 100644 --- a/src/share/classes/sun/security/jgss/SunProvider.java +++ b/src/share/classes/sun/security/jgss/SunProvider.java @@ -62,7 +62,7 @@ public final class SunProvider extends Provider { public SunProvider() { /* We are the Sun JGSS provider */ - super("SunJGSS", 1.0, INFO); + super("SunJGSS", 1.7d, INFO); AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index d7c5484ec0c337b9f8d3205fc98e133f79d2e2da..388548b2eebde6bed889a918ca226f96302b86c0 100644 --- a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.File; +import java.util.Comparator; import java.util.StringTokenizer; /** @@ -229,10 +230,11 @@ public class KeyTab implements KeyTabConstants { /** * Reads the service key from the keytab file. * @param service the PrincipalName of the requested service. - * @return the last service key in the keytab + * @return the last service key in the keytab with the highest kvno */ public EncryptionKey readServiceKey(PrincipalName service) { KeyTabEntry entry = null; + EncryptionKey key = null; if (entries != null) { // Find latest entry for this service that has an etype // that has been configured for use @@ -240,9 +242,12 @@ public class KeyTab implements KeyTabConstants { entry = entries.elementAt(i); if (entry.service.match(service)) { if (EType.isSupported(entry.keyType)) { - return new EncryptionKey(entry.keyblock, + if (key == null || + entry.keyVersion > key.getKeyVersionNumber()) { + key = new EncryptionKey(entry.keyblock, entry.keyType, new Integer(entry.keyVersion)); + } } else if (DEBUG) { System.out.println("Found unsupported keytype (" + entry.keyType + ") for " + service); @@ -250,12 +255,13 @@ public class KeyTab implements KeyTabConstants { } } } - return null; + return key; } /** * Reads all keys for a service from the keytab file that have - * etypes that have been configured for use. + * etypes that have been configured for use. If there are multiple + * keys with same etype, the one with the highest kvno is returned. * @param service the PrincipalName of the requested service * @return an array containing all the service keys */ @@ -288,49 +294,39 @@ public class KeyTab implements KeyTabConstants { size = keys.size(); if (size == 0) return null; - EncryptionKey[] retVal = new EncryptionKey[size]; + EncryptionKey[] retVal = keys.toArray(new EncryptionKey[size]); // Sort keys according to default_tkt_enctypes - int pos = 0; - EncryptionKey k; if (DEBUG) { System.out.println("Ordering keys wrt default_tkt_enctypes list"); } - int[] etypes = EType.getDefaults("default_tkt_enctypes"); - if (etypes == null || etypes == EType.getBuiltInDefaults()) { - // Either no supported types specified in default_tkt_enctypes - // or no default_tkt_enctypes entry at all. For both cases, - // just return supported keys in the order retrieved - for (int i = 0; i < size; i++) { - retVal[pos++] = keys.get(i); - } - } else { - for (int j = 0; j < etypes.length && pos < size; j++) { - int target = etypes[j]; - for (int i = 0; i < size && pos < size; i++) { - k = keys.get(i); - if (k != null && k.getEType() == target) { - if (DEBUG) { - System.out.println(pos + ": " + k); + + final int[] etypes = EType.getDefaults("default_tkt_enctypes"); + + // Sort the keys, k1 is preferred than k2 if: + // 1. k1's etype appears earlier in etypes than k2's + // 2. If same, k1's KVNO is higher + Arrays.sort(retVal, new Comparator() { + @Override + public int compare(EncryptionKey o1, EncryptionKey o2) { + if (etypes != null && etypes != EType.getBuiltInDefaults()) { + int o1EType = o1.getEType(); + int o2EType = o2.getEType(); + if (o1EType != o2EType) { + for (int i=0; i() { public Void run() { put("TerminalFactory.PC/SC", "sun.security.smartcardio.SunPCSC$Factory"); diff --git a/src/share/classes/sun/security/ssl/SunJSSE.java b/src/share/classes/sun/security/ssl/SunJSSE.java index a097ebb428bcd237a98794afd9105eccca937b2a..0811fc0d83b1cd77994aae8c437e2ed468c05944 100644 --- a/src/share/classes/sun/security/ssl/SunJSSE.java +++ b/src/share/classes/sun/security/ssl/SunJSSE.java @@ -103,7 +103,7 @@ public abstract class SunJSSE extends java.security.Provider { // standard constructor protected SunJSSE() { - super("SunJSSE", 1.6d, info); + super("SunJSSE", 1.7d, info); subclassCheck(); if (Boolean.TRUE.equals(fips)) { throw new ProviderException diff --git a/src/share/classes/sun/security/util/Password.java b/src/share/classes/sun/security/util/Password.java index 5600ed60b17da82858cbde5ba7248a3f174b5c45..9f767124d491d117100b2e89633874b06c9b2189 100644 --- a/src/share/classes/sun/security/util/Password.java +++ b/src/share/classes/sun/security/util/Password.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,14 @@ import java.util.Arrays; public class Password { /** Reads user password from given input stream. */ public static char[] readPassword(InputStream in) throws IOException { + return readPassword(in, false); + } + + /** Reads user password from given input stream. + * @param isEchoOn true if the password should be echoed on the screen + */ + public static char[] readPassword(InputStream in, boolean isEchoOn) + throws IOException { char[] consoleEntered = null; byte[] consoleBytes = null; @@ -44,7 +52,7 @@ public class Password { try { // Use the new java.io.Console class Console con = null; - if (in == System.in && ((con = System.console()) != null)) { + if (!isEchoOn && in == System.in && ((con = System.console()) != null)) { consoleEntered = con.readPassword(); // readPassword returns "" if you just print ENTER, // to be compatible with old Password class, change to null diff --git a/src/share/native/sun/security/ec/ec.c b/src/share/native/sun/security/ec/ec.c index d77f110af645e42328e15660cdd225c85dc557a5..0eda7da753b9ce0388666465a118b164dc28eabd 100644 --- a/src/share/native/sun/security/ec/ec.c +++ b/src/share/native/sun/security/ec/ec.c @@ -422,7 +422,7 @@ ec_GenerateRandomPrivateKey(const unsigned char *order, int len, */ if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup; if (randomlen != 2 * len) { - goto cleanup; + randomlen = 2 * len; } /* No need to generate - random bytes are now supplied */ /* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/ diff --git a/src/solaris/classes/sun/nio/ch/EPollPort.java b/src/solaris/classes/sun/nio/ch/EPollPort.java index a79cb731841ad6c212a472242e5f9f9aac58883a..5618cd8fba0dd85e7e03d66d60d9ff16f98b0d3b 100644 --- a/src/solaris/classes/sun/nio/ch/EPollPort.java +++ b/src/solaris/classes/sun/nio/ch/EPollPort.java @@ -248,12 +248,13 @@ final class EPollPort public void run() { Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); boolean replaceMe = false; Event ev; try { for (;;) { // reset invoke count - if (myGroupAndInvokeCount != null) + if (isPooledThread) myGroupAndInvokeCount.resetInvokeCount(); try { @@ -289,7 +290,7 @@ final class EPollPort // process event try { - ev.channel().onEvent(ev.events()); + ev.channel().onEvent(ev.events(), isPooledThread); } catch (Error x) { replaceMe = true; throw x; } catch (RuntimeException x) { diff --git a/src/solaris/classes/sun/nio/ch/Port.java b/src/solaris/classes/sun/nio/ch/Port.java index 8b19637bc2a2608452c91591fb8eb1540e6b5fc2..db623265b2ba5c9bb16cab209d9e8fe348e6791d 100644 --- a/src/solaris/classes/sun/nio/ch/Port.java +++ b/src/solaris/classes/sun/nio/ch/Port.java @@ -49,7 +49,7 @@ abstract class Port extends AsynchronousChannelGroupImpl { * Implemented by clients registered with this port. */ interface PollableChannel extends Closeable { - void onEvent(int events); + void onEvent(int events, boolean mayInvokeDirect); } // maps fd to "pollable" channel @@ -121,7 +121,7 @@ abstract class Port extends AsynchronousChannelGroupImpl { final Object attachForeignChannel(final Channel channel, FileDescriptor fd) { int fdVal = IOUtil.fdVal(fd); register(fdVal, new PollableChannel() { - public void onEvent(int events) { } + public void onEvent(int events, boolean mayInvokeDirect) { } public void close() throws IOException { channel.close(); } diff --git a/src/solaris/classes/sun/nio/ch/SolarisEventPort.java b/src/solaris/classes/sun/nio/ch/SolarisEventPort.java index 908eecce02420fe654ae2d01ae13a9630c708249..1df7a0ba04474177e748556290ab567526071e86 100644 --- a/src/solaris/classes/sun/nio/ch/SolarisEventPort.java +++ b/src/solaris/classes/sun/nio/ch/SolarisEventPort.java @@ -151,12 +151,13 @@ class SolarisEventPort public void run() { Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); boolean replaceMe = false; long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT); try { for (;;) { // reset invoke count - if (myGroupAndInvokeCount != null) + if (isPooledThread) myGroupAndInvokeCount.resetInvokeCount(); // wait for I/O completion event @@ -205,7 +206,7 @@ class SolarisEventPort if (ch != null) { replaceMe = true; // no need to translate events - ch.onEvent(events); + ch.onEvent(events, isPooledThread); } } } finally { diff --git a/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java b/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java index 1a8c92352d2406f3d8db22c419ebe7ce38a381c7..15fab5e18121035ccc10f50eb0d5f36b7f0449ca 100644 --- a/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java +++ b/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java @@ -59,10 +59,13 @@ class UnixAsynchronousServerSocketChannelImpl private final Object updateLock = new Object(); // pending accept - private PendingFuture pendingAccept; + private boolean acceptPending; + private CompletionHandler acceptHandler; + private Object acceptAttachment; + private PendingFuture acceptFuture; // context for permission check when security manager set - private AccessControlContext acc; + private AccessControlContext acceptAcc; UnixAsynchronousServerSocketChannelImpl(Port port) @@ -83,15 +86,6 @@ class UnixAsynchronousServerSocketChannelImpl port.register(fdVal, this); } - // returns and clears the result of a pending accept - private PendingFuture grabPendingAccept() { - synchronized (updateLock) { - PendingFuture result = pendingAccept; - pendingAccept = null; - return result; - } - } - @Override void implClose() throws IOException { // remove the mapping @@ -101,17 +95,27 @@ class UnixAsynchronousServerSocketChannelImpl nd.close(fd); // if there is a pending accept then complete it - final PendingFuture result = - grabPendingAccept(); - if (result != null) { - // discard the stack trace as otherwise it may appear that implClose - // has thrown the exception. - AsynchronousCloseException x = new AsynchronousCloseException(); - x.setStackTrace(new StackTraceElement[0]); - result.setFailure(x); + CompletionHandler handler; + Object att; + PendingFuture future; + synchronized (updateLock) { + if (!acceptPending) + return; // no pending accept + acceptPending = false; + handler = acceptHandler; + att = acceptAttachment; + future = acceptFuture; + } + // discard the stack trace as otherwise it may appear that implClose + // has thrown the exception. + AsynchronousCloseException x = new AsynchronousCloseException(); + x.setStackTrace(new StackTraceElement[0]); + if (handler == null) { + future.setFailure(x); + } else { // invoke by submitting task rather than directly - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(this, handler, att, null, x); } } @@ -124,15 +128,17 @@ class UnixAsynchronousServerSocketChannelImpl * Invoked by event handling thread when listener socket is polled */ @Override - public void onEvent(int events) { - PendingFuture result = grabPendingAccept(); - if (result == null) - return; // may have been grabbed by asynchronous close + public void onEvent(int events, boolean mayInvokeDirect) { + synchronized (updateLock) { + if (!acceptPending) + return; // may have been grabbed by asynchronous close + acceptPending = false; + } // attempt to accept connection FileDescriptor newfd = new FileDescriptor(); InetSocketAddress[] isaa = new InetSocketAddress[1]; - boolean accepted = false; + Throwable exc = null; try { begin(); int n = accept0(this.fd, newfd, isaa); @@ -140,49 +146,52 @@ class UnixAsynchronousServerSocketChannelImpl // spurious wakeup, is this possible? if (n == IOStatus.UNAVAILABLE) { synchronized (updateLock) { - this.pendingAccept = result; + acceptPending = true; } port.startPoll(fdVal, Port.POLLIN); return; } - // connection accepted - accepted = true; - } catch (Throwable x) { if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - enableAccept(); - result.setFailure(x); + exc = x; } finally { end(); } // Connection accepted so finish it when not holding locks. AsynchronousSocketChannel child = null; - if (accepted) { + if (exc == null) { try { - child = finishAccept(newfd, isaa[0], acc); - enableAccept(); - result.setResult(child); + child = finishAccept(newfd, isaa[0], acceptAcc); } catch (Throwable x) { - enableAccept(); if (!(x instanceof IOException) && !(x instanceof SecurityException)) x = new IOException(x); - result.setFailure(x); + exc = x; } } - // if an async cancel has already cancelled the operation then - // close the new channel so as to free resources - if (child != null && result.isCancelled()) { - try { - child.close(); - } catch (IOException ignore) { } - } + // copy field befores accept is re-renabled + CompletionHandler handler = acceptHandler; + Object att = acceptAttachment; + PendingFuture future = acceptFuture; - // invoke the handler - Invoker.invoke(result.handler(), result); + // re-enable accepting and invoke handler + enableAccept(); + + if (handler == null) { + future.setResult(child, exc); + // if an async cancel has already cancelled the operation then + // close the new channel so as to free resources + if (child != null && future.isCancelled()) { + try { + child.close(); + } catch (IOException ignore) { } + } + } else { + Invoker.invoke(this, handler, att, child, exc); + } } /** @@ -234,16 +243,18 @@ class UnixAsynchronousServerSocketChannelImpl } @Override - @SuppressWarnings("unchecked") - public Future accept(A attachment, - final CompletionHandler handler) + Future implAccept(Object att, + CompletionHandler handler) { // complete immediately if channel is closed if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invokeIndirectly(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) { + return CompletedFuture.withFailure(e); + } else { + Invoker.invoke(this, handler, att, null, e); + return null; + } } if (localAddress == null) throw new NotYetBoundException(); @@ -258,25 +269,31 @@ class UnixAsynchronousServerSocketChannelImpl throw new AcceptPendingException(); // attempt accept - AbstractFuture result = null; FileDescriptor newfd = new FileDescriptor(); InetSocketAddress[] isaa = new InetSocketAddress[1]; + Throwable exc = null; try { begin(); int n = accept0(this.fd, newfd, isaa); if (n == IOStatus.UNAVAILABLE) { - // no connection to accept - result = new PendingFuture(this, handler, attachment); // need calling context when there is security manager as // permission check may be done in a different thread without // any application call frames on the stack - synchronized (this) { - this.acc = (System.getSecurityManager() == null) ? + PendingFuture result = null; + synchronized (updateLock) { + if (handler == null) { + this.acceptHandler = null; + result = new PendingFuture(this); + this.acceptFuture = result; + } else { + this.acceptHandler = handler; + this.acceptAttachment = att; + } + this.acceptAcc = (System.getSecurityManager() == null) ? null : AccessController.getContext(); - this.pendingAccept = - (PendingFuture)result; + this.acceptPending = true; } // register for connections @@ -287,25 +304,30 @@ class UnixAsynchronousServerSocketChannelImpl // accept failed if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } finally { end(); } - // connection accepted immediately - if (result == null) { + AsynchronousSocketChannel child = null; + if (exc == null) { + // connection accepted immediately try { - AsynchronousSocketChannel ch = finishAccept(newfd, isaa[0], null); - result = CompletedFuture.withResult(this, ch, attachment); + child = finishAccept(newfd, isaa[0], null); } catch (Throwable x) { - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } } - // re-enable accepting and invoke handler + // re-enable accepting before invoking handler enableAccept(); - Invoker.invokeIndirectly(handler, result); - return result; + + if (handler == null) { + return CompletedFuture.withResult(child, exc); + } else { + Invoker.invokeIndirectly(this, handler, att, child, exc); + return null; + } } // -- Native methods -- diff --git a/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index e80f202bdff96c2324a63f36d4d82bedc1faab9c..536b0e2ca83bc08d9c4529780b6f8879971cedf0 100644 --- a/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -61,20 +61,33 @@ class UnixAsynchronousSocketChannelImpl private final Object updateLock = new Object(); // pending connect (updateLock) - private PendingFuture pendingConnect; + private boolean connectPending; + private CompletionHandler connectHandler; + private Object connectAttachment; + private PendingFuture connectFuture; - // pending remote address (statLock) + // pending remote address (stateLock) private SocketAddress pendingRemote; // pending read (updateLock) + private boolean readPending; + private boolean isScatteringRead; + private ByteBuffer readBuffer; private ByteBuffer[] readBuffers; - private boolean scatteringRead; - private PendingFuture pendingRead; + private CompletionHandler readHandler; + private Object readAttachment; + private PendingFuture readFuture; + private Future readTimer; // pending write (updateLock) + private boolean writePending; + private boolean isGatheringWrite; + private ByteBuffer writeBuffer; private ByteBuffer[] writeBuffers; - private boolean gatheringWrite; - private PendingFuture pendingWrite; + private CompletionHandler writeHandler; + private Object writeAttachment; + private PendingFuture writeFuture; + private Future writeTimer; UnixAsynchronousSocketChannelImpl(Port port) @@ -128,43 +141,36 @@ class UnixAsynchronousSocketChannelImpl private void updateEvents() { assert Thread.holdsLock(updateLock); int events = 0; - if (pendingRead != null) + if (readPending) events |= Port.POLLIN; - if (pendingConnect != null || pendingWrite != null) + if (connectPending || writePending) events |= Port.POLLOUT; if (events != 0) port.startPoll(fdVal, events); } - /** - * Invoked by event handler thread when file descriptor is polled - */ - @Override - public void onEvent(int events) { - boolean readable = (events & Port.POLLIN) > 0; - boolean writable = (events & Port.POLLOUT) > 0; - if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) { - readable = true; - writable = true; - } - - PendingFuture connectResult = null; - PendingFuture readResult = null; - PendingFuture writeResult = null; + // invoke to finish read and/or write operations + private void finish(boolean mayInvokeDirect, + boolean readable, + boolean writable) + { + boolean finishRead = false; + boolean finishWrite = false; + boolean finishConnect = false; // map event to pending result synchronized (updateLock) { - if (readable && (pendingRead != null)) { - readResult = pendingRead; - pendingRead = null; + if (readable && this.readPending) { + this.readPending = false; + finishRead = true; } if (writable) { - if (pendingWrite != null) { - writeResult = pendingWrite; - pendingWrite = null; - } else if (pendingConnect != null) { - connectResult = pendingConnect; - pendingConnect = null; + if (this.writePending) { + this.writePending = false; + finishWrite = true; + } else if (this.connectPending) { + this.connectPending = false; + finishConnect = true; } } } @@ -172,36 +178,32 @@ class UnixAsynchronousSocketChannelImpl // complete the I/O operation. Special case for when channel is // ready for both reading and writing. In that case, submit task to // complete write if write operation has a completion handler. - if (readResult != null) { - if (writeResult != null) - finishWrite(writeResult, false); - finishRead(readResult, true); + if (finishRead) { + if (finishWrite) + finishWrite(false); + finishRead(mayInvokeDirect); return; } - if (writeResult != null) { - finishWrite(writeResult, true); - } - if (connectResult != null) { - finishConnect(connectResult, true); + if (finishWrite) { + finishWrite(mayInvokeDirect); } - } - - // returns and clears the result of a pending read - PendingFuture grabPendingRead() { - synchronized (updateLock) { - PendingFuture result = pendingRead; - pendingRead = null; - return result; + if (finishConnect) { + finishConnect(mayInvokeDirect); } } - // returns and clears the result of a pending write - PendingFuture grabPendingWrite() { - synchronized (updateLock) { - PendingFuture result = pendingWrite; - pendingWrite = null; - return result; + /** + * Invoked by event handler thread when file descriptor is polled + */ + @Override + public void onEvent(int events, boolean mayInvokeDirect) { + boolean readable = (events & Port.POLLIN) > 0; + boolean writable = (events & Port.POLLOUT) > 0; + if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) { + readable = true; + writable = true; } + finish(mayInvokeDirect, readable, writable); } @Override @@ -213,26 +215,7 @@ class UnixAsynchronousSocketChannelImpl nd.close(fd); // All outstanding I/O operations are required to fail - final PendingFuture readyToConnect; - final PendingFuture readyToRead; - final PendingFuture readyToWrite; - synchronized (updateLock) { - readyToConnect = pendingConnect; - pendingConnect = null; - readyToRead = pendingRead; - pendingRead = null; - readyToWrite = pendingWrite; - pendingWrite = null; - } - if (readyToConnect != null) { - finishConnect(readyToConnect, false); - } - if (readyToRead != null) { - finishRead(readyToRead, false); - } - if (readyToWrite != null) { - finishWrite(readyToWrite, false); - } + finish(false, true, true); } @Override @@ -240,9 +223,9 @@ class UnixAsynchronousSocketChannelImpl if (task.getContext() == OpType.CONNECT) killConnect(); if (task.getContext() == OpType.READ) - killConnect(); + killReading(); if (task.getContext() == OpType.WRITE) - killConnect(); + killWriting(); } // -- connect -- @@ -255,15 +238,12 @@ class UnixAsynchronousSocketChannelImpl } } - private void finishConnect(PendingFuture result, - boolean invokeDirect) - { + private void finishConnect(boolean mayInvokeDirect) { Throwable e = null; try { begin(); checkConnect(fdVal); setConnected(); - result.setResult(null); } catch (Throwable x) { if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); @@ -276,26 +256,38 @@ class UnixAsynchronousSocketChannelImpl try { close(); } catch (IOException ignore) { } - result.setFailure(e); } - if (invokeDirect) { - Invoker.invoke(result.handler(), result); + + + // invoke handler and set result + CompletionHandler handler = connectHandler; + Object att = connectAttachment; + PendingFuture future = connectFuture; + if (handler == null) { + future.setResult(null, e); } else { - Invoker.invokeIndirectly(result.handler(), result); + if (mayInvokeDirect) { + Invoker.invokeUnchecked(handler, att, null, e); + } else { + Invoker.invokeIndirectly(this, handler, att, null, e); + } } } @Override @SuppressWarnings("unchecked") - public Future connect(SocketAddress remote, - A attachment, - CompletionHandler handler) + Future implConnect(SocketAddress remote, + A attachment, + CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) { + return CompletedFuture.withFailure(e); + } else { + Invoker.invoke(this, handler, attachment, null, e); + return null; + } } InetSocketAddress isa = Net.checkAddress(remote); @@ -317,7 +309,6 @@ class UnixAsynchronousSocketChannelImpl notifyBeforeTcpConnect = (localAddress == null); } - AbstractFuture result = null; Throwable e = null; try { begin(); @@ -327,15 +318,21 @@ class UnixAsynchronousSocketChannelImpl int n = Net.connect(fd, isa.getAddress(), isa.getPort()); if (n == IOStatus.UNAVAILABLE) { // connection could not be established immediately - result = new PendingFuture(this, handler, attachment, OpType.CONNECT); + PendingFuture result = null; synchronized (updateLock) { - this.pendingConnect = (PendingFuture)result; + if (handler == null) { + result = new PendingFuture(this, OpType.CONNECT); + this.connectFuture = (PendingFuture)result; + } else { + this.connectHandler = (CompletionHandler)handler; + this.connectAttachment = attachment; + } + this.connectPending = true; updateEvents(); } return result; } setConnected(); - result = CompletedFuture.withResult(this, null, attachment); } catch (Throwable x) { if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); @@ -349,84 +346,111 @@ class UnixAsynchronousSocketChannelImpl try { close(); } catch (IOException ignore) { } - result = CompletedFuture.withFailure(this, e, attachment); } - - Invoker.invoke(handler, result); - return result; + if (handler == null) { + return CompletedFuture.withResult(null, e); + } else { + Invoker.invoke(this, handler, attachment, null, e); + return null; + } } // -- read -- - @SuppressWarnings("unchecked") - private void finishRead(PendingFuture result, - boolean invokeDirect) - { + private void finishRead(boolean mayInvokeDirect) { int n = -1; - PendingFuture pending = null; + Throwable exc = null; + + // copy fields as we can't access them after reading is re-enabled. + boolean scattering = isScatteringRead; + CompletionHandler handler = readHandler; + Object att = readAttachment; + PendingFuture future = readFuture; + Future timeout = readTimer; + try { begin(); - ByteBuffer[] dsts = readBuffers; - if (dsts.length == 1) { - n = IOUtil.read(fd, dsts[0], -1, nd, null); + if (scattering) { + n = (int)IOUtil.read(fd, readBuffers, nd); } else { - n = (int)IOUtil.read(fd, dsts, nd); + n = IOUtil.read(fd, readBuffer, -1, nd, null); } if (n == IOStatus.UNAVAILABLE) { // spurious wakeup, is this possible? - pending = result; + synchronized (updateLock) { + readPending = true; + } return; } - // allow buffer(s) to be GC'ed. - readBuffers = null; + // allow objects to be GC'ed. + this.readBuffer = null; + this.readBuffers = null; + this.readAttachment = null; // allow another read to be initiated - boolean wasScatteringRead = scatteringRead; enableReading(); - // result is Integer or Long - if (wasScatteringRead) { - result.setResult(Long.valueOf(n)); - } else { - result.setResult(Integer.valueOf(n)); - } - } catch (Throwable x) { enableReading(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { // restart poll in case of concurrent write synchronized (updateLock) { - if (pending != null) - this.pendingRead = pending; updateEvents(); } end(); } - if (invokeDirect) { - Invoker.invoke(result.handler(), result); + // cancel the associated timer + if (timeout != null) + timeout.cancel(false); + + // create result + Number result = (exc != null) ? null : (scattering) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // invoke handler or set result + if (handler == null) { + future.setResult(result, exc); } else { - Invoker.invokeIndirectly(result.handler(), result); + if (mayInvokeDirect) { + Invoker.invokeUnchecked(handler, att, result, exc); + } else { + Invoker.invokeIndirectly(this, handler, att, result, exc); + } } } private Runnable readTimeoutTask = new Runnable() { public void run() { - PendingFuture result = grabPendingRead(); - if (result == null) - return; // already completed + CompletionHandler handler = null; + Object att = null; + PendingFuture future = null; + + synchronized (updateLock) { + if (!readPending) + return; + readPending = false; + handler = readHandler; + att = readAttachment; + future = readFuture; + } // kill further reading before releasing waiters enableReading(true); - // set completed and invoke handler - result.setFailure(new InterruptedByTimeoutException()); - Invoker.invokeIndirectly(result.handler(), result); + // invoke handler or set result + Exception exc = new InterruptedByTimeoutException(); + if (handler == null) { + future.setFailure(exc); + } else { + AsynchronousChannel ch = UnixAsynchronousSocketChannelImpl.this; + Invoker.invokeIndirectly(ch, handler, att, null, exc); + } } }; @@ -435,8 +459,9 @@ class UnixAsynchronousSocketChannelImpl */ @Override @SuppressWarnings("unchecked") - Future readImpl(ByteBuffer[] dsts, - boolean isScatteringRead, + Future implRead(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, @@ -450,144 +475,178 @@ class UnixAsynchronousSocketChannelImpl boolean invokeDirect = false; boolean attemptRead = false; if (!disableSynchronousRead) { - myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); - invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); - attemptRead = (handler == null) || invokeDirect || - !port.isFixedThreadPool(); // okay to attempt read with user thread pool + if (handler == null) { + attemptRead = true; + } else { + myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); + // okay to attempt read with user thread pool + attemptRead = invokeDirect || !port.isFixedThreadPool(); + } } - AbstractFuture result; + int n = IOStatus.UNAVAILABLE; + Throwable exc = null; + boolean pending = false; + try { begin(); - int n; if (attemptRead) { if (isScatteringRead) { n = (int)IOUtil.read(fd, dsts, nd); } else { - n = IOUtil.read(fd, dsts[0], -1, nd, null); + n = IOUtil.read(fd, dst, -1, nd, null); } - } else { - n = IOStatus.UNAVAILABLE; } if (n == IOStatus.UNAVAILABLE) { - result = new PendingFuture(this, handler, attachment, OpType.READ); - - // update evetns so that read will complete asynchronously + PendingFuture result = null; synchronized (updateLock) { + this.isScatteringRead = isScatteringRead; + this.readBuffer = dst; this.readBuffers = dsts; - this.scatteringRead = isScatteringRead; - this.pendingRead = (PendingFuture)result; + if (handler == null) { + this.readHandler = null; + result = new PendingFuture(this, OpType.READ); + this.readFuture = (PendingFuture)result; + this.readAttachment = null; + } else { + this.readHandler = (CompletionHandler)handler; + this.readAttachment = attachment; + this.readFuture = null; + } + if (timeout > 0L) { + this.readTimer = port.schedule(readTimeoutTask, timeout, unit); + } + this.readPending = true; updateEvents(); } - - // schedule timeout - if (timeout > 0L) { - Future timeoutTask = - port.schedule(readTimeoutTask, timeout, unit); - ((PendingFuture)result).setTimeoutTask(timeoutTask); - } + pending = true; return result; } - - // data available - enableReading(); - - // result type is Long or Integer - if (isScatteringRead) { - result = (CompletedFuture)CompletedFuture - .withResult(this, Long.valueOf(n), attachment); - } else { - result = (CompletedFuture)CompletedFuture - .withResult(this, Integer.valueOf(n), attachment); - } } catch (Throwable x) { - enableReading(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } finally { + if (!pending) + enableReading(); end(); } - if (invokeDirect) { - Invoker.invokeDirect(myGroupAndInvokeCount, handler, result); + Number result = (exc != null) ? null : (isScatteringRead) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // read completed immediately + if (handler != null) { + if (invokeDirect) { + Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc); + } else { + Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc); + } + return null; } else { - Invoker.invokeIndirectly(handler, result); + return CompletedFuture.withResult((V)result, exc); } - return result; } // -- write -- - private void finishWrite(PendingFuture result, - boolean invokeDirect) - { - PendingFuture pending = null; + private void finishWrite(boolean mayInvokeDirect) { + int n = -1; + Throwable exc = null; + + // copy fields as we can't access them after reading is re-enabled. + boolean gathering = this.isGatheringWrite; + CompletionHandler handler = this.writeHandler; + Object att = this.writeAttachment; + PendingFuture future = this.writeFuture; + Future timer = this.writeTimer; + try { begin(); - ByteBuffer[] srcs = writeBuffers; - int n; - if (srcs.length == 1) { - n = IOUtil.write(fd, srcs[0], -1, nd, null); + if (gathering) { + n = (int)IOUtil.write(fd, writeBuffers, nd); } else { - n = (int)IOUtil.write(fd, srcs, nd); + n = IOUtil.write(fd, writeBuffer, -1, nd, null); } if (n == IOStatus.UNAVAILABLE) { // spurious wakeup, is this possible? - pending = result; + synchronized (updateLock) { + writePending = true; + } return; } - // allow buffer(s) to be GC'ed. - writeBuffers = null; + // allow objects to be GC'ed. + this.writeBuffer = null; + this.writeBuffers = null; + this.writeAttachment = null; // allow another write to be initiated - boolean wasGatheringWrite = gatheringWrite; enableWriting(); - // result is a Long or Integer - if (wasGatheringWrite) { - result.setResult(Long.valueOf(n)); - } else { - result.setResult(Integer.valueOf(n)); - } - } catch (Throwable x) { enableWriting(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { - // restart poll in case of concurrent read - synchronized (this) { - if (pending != null) - this.pendingWrite = pending; + // restart poll in case of concurrent write + synchronized (updateLock) { updateEvents(); } end(); } - if (invokeDirect) { - Invoker.invoke(result.handler(), result); + + // cancel the associated timer + if (timer != null) + timer.cancel(false); + + // create result + Number result = (exc != null) ? null : (gathering) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // invoke handler or set result + if (handler == null) { + future.setResult(result, exc); } else { - Invoker.invokeIndirectly(result.handler(), result); + if (mayInvokeDirect) { + Invoker.invokeUnchecked(handler, att, result, exc); + } else { + Invoker.invokeIndirectly(this, handler, att, result, exc); + } } } private Runnable writeTimeoutTask = new Runnable() { public void run() { - PendingFuture result = grabPendingWrite(); - if (result == null) - return; // already completed + CompletionHandler handler = null; + Object att = null; + PendingFuture future = null; + + synchronized (updateLock) { + if (!writePending) + return; + writePending = false; + handler = writeHandler; + att = writeAttachment; + future = writeFuture; + } // kill further writing before releasing waiters enableWriting(true); - // set completed and invoke handler - result.setFailure(new InterruptedByTimeoutException()); - Invoker.invokeIndirectly(result.handler(), result); + // invoke handler or set result + Exception exc = new InterruptedByTimeoutException(); + if (handler != null) { + Invoker.invokeIndirectly(UnixAsynchronousSocketChannelImpl.this, + handler, att, null, exc); + } else { + future.setFailure(exc); + } } }; @@ -596,8 +655,9 @@ class UnixAsynchronousSocketChannelImpl */ @Override @SuppressWarnings("unchecked") - Future writeImpl(ByteBuffer[] srcs, - boolean isGatheringWrite, + Future implWrite(boolean isGatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, @@ -607,66 +667,72 @@ class UnixAsynchronousSocketChannelImpl Invoker.getGroupAndInvokeCount(); boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); boolean attemptWrite = (handler == null) || invokeDirect || - !port.isFixedThreadPool(); // okay to attempt read with user thread pool + !port.isFixedThreadPool(); // okay to attempt write with user thread pool + + int n = IOStatus.UNAVAILABLE; + Throwable exc = null; + boolean pending = false; - AbstractFuture result; try { begin(); - int n; if (attemptWrite) { if (isGatheringWrite) { n = (int)IOUtil.write(fd, srcs, nd); } else { - n = IOUtil.write(fd, srcs[0], -1, nd, null); + n = IOUtil.write(fd, src, -1, nd, null); } - } else { - n = IOStatus.UNAVAILABLE; } if (n == IOStatus.UNAVAILABLE) { - result = new PendingFuture(this, handler, attachment, OpType.WRITE); - - // update evetns so that read will complete asynchronously + PendingFuture result = null; synchronized (updateLock) { + this.isGatheringWrite = isGatheringWrite; + this.writeBuffer = src; this.writeBuffers = srcs; - this.gatheringWrite = isGatheringWrite; - this.pendingWrite = (PendingFuture)result; + if (handler == null) { + this.writeHandler = null; + result = new PendingFuture(this, OpType.WRITE); + this.writeFuture = (PendingFuture)result; + this.writeAttachment = null; + } else { + this.writeHandler = (CompletionHandler)handler; + this.writeAttachment = attachment; + this.writeFuture = null; + } + if (timeout > 0L) { + this.writeTimer = port.schedule(writeTimeoutTask, timeout, unit); + } + this.writePending = true; updateEvents(); } - - // schedule timeout - if (timeout > 0L) { - Future timeoutTask = - port.schedule(writeTimeoutTask, timeout, unit); - ((PendingFuture)result).setTimeoutTask(timeoutTask); - } + pending = true; return result; } - - // data available - enableWriting(); - if (isGatheringWrite) { - result = (CompletedFuture)CompletedFuture - .withResult(this, Long.valueOf(n), attachment); - } else { - result = (CompletedFuture)CompletedFuture - .withResult(this, Integer.valueOf(n), attachment); - } } catch (Throwable x) { - enableWriting(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } finally { + if (!pending) + enableWriting(); end(); } - if (invokeDirect) { - Invoker.invokeDirect(myGroupAndInvokeCount, handler, result); + + Number result = (exc != null) ? null : (isGatheringWrite) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // write completed immediately + if (handler != null) { + if (invokeDirect) { + Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc); + } else { + Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc); + } + return null; } else { - Invoker.invokeIndirectly(handler, result); + return CompletedFuture.withResult((V)result, exc); } - return result; } // -- Native methods -- diff --git a/src/solaris/classes/sun/nio/fs/UnixPath.java b/src/solaris/classes/sun/nio/fs/UnixPath.java index 9d5db356255cee5b9d776ac86164d2ab74eb08f5..2741915e55de28253e03fabd54154346261f838b 100644 --- a/src/solaris/classes/sun/nio/fs/UnixPath.java +++ b/src/solaris/classes/sun/nio/fs/UnixPath.java @@ -65,9 +65,6 @@ class UnixPath // array of offsets of elements in path (created lazily) private volatile int[] offsets; - // file permissions (created lazily) - private volatile FilePermission[] perms; - UnixPath(UnixFileSystem fs, byte[] path) { this.fs = fs; this.path = path; @@ -768,45 +765,23 @@ class UnixPath } } - // create file permissions used for read and write checks - private void checkReadOrWrite(boolean checkRead) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) - return; - if (perms == null) { - synchronized (this) { - if (perms == null) { - FilePermission[] p = new FilePermission[2]; - String pathForPermCheck = getPathForPermissionCheck(); - p[0] = new FilePermission(pathForPermCheck, - SecurityConstants.FILE_READ_ACTION); - p[1] = new FilePermission(pathForPermCheck, - SecurityConstants.FILE_WRITE_ACTION); - perms = p; - } - } - } - if (checkRead) { - sm.checkPermission(perms[0]); - } else { - sm.checkPermission(perms[1]); - } - } void checkRead() { - checkReadOrWrite(true); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkRead(getPathForPermissionCheck()); } void checkWrite() { - checkReadOrWrite(false); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkWrite(getPathForPermissionCheck()); } void checkDelete() { SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - // permission not cached + if (sm != null) sm.checkDelete(getPathForPermissionCheck()); - } } @Override diff --git a/src/windows/classes/sun/nio/ch/Iocp.java b/src/windows/classes/sun/nio/ch/Iocp.java index b4c2cdef61e469dbb8326d6c0e7389891a33813e..97467fc7c0070d137b55d7c51e9f43c15c953a0b 100644 --- a/src/windows/classes/sun/nio/ch/Iocp.java +++ b/src/windows/classes/sun/nio/ch/Iocp.java @@ -34,6 +34,8 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; import sun.misc.Unsafe; /** @@ -44,6 +46,7 @@ import sun.misc.Unsafe; class Iocp extends AsynchronousChannelGroupImpl { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long INVALID_HANDLE_VALUE = -1L; + private static final boolean supportsThreadAgnosticIo; // maps completion key to channel private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock(); @@ -87,6 +90,13 @@ class Iocp extends AsynchronousChannelGroupImpl { PendingFuture getByOverlapped(long overlapped); } + /** + * Indicates if this operating system supports thread agnostic I/O. + */ + static boolean supportsThreadAgnosticIo() { + return supportsThreadAgnosticIo; + } + // release all resources void implClose() { synchronized (this) { @@ -216,8 +226,9 @@ class Iocp extends AsynchronousChannelGroupImpl { } while ((key == 0) || keyToChannel.containsKey(key)); // associate with I/O completion port - if (handle != 0L) + if (handle != 0L) { createIoCompletionPort(handle, port, key, 0); + } // setup mapping keyToChannel.put(key, ch); @@ -282,7 +293,7 @@ class Iocp extends AsynchronousChannelGroupImpl { /** * Invoked if the I/O operation completes successfully. */ - public void completed(int bytesTransferred); + public void completed(int bytesTransferred, boolean canInvokeDirect); /** * Invoked if the I/O operation fails. @@ -305,6 +316,7 @@ class Iocp extends AsynchronousChannelGroupImpl { public void run() { Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + boolean canInvokeDirect = (myGroupAndInvokeCount != null); CompletionStatus ioResult = new CompletionStatus(); boolean replaceMe = false; @@ -382,7 +394,7 @@ class Iocp extends AsynchronousChannelGroupImpl { ResultHandler rh = (ResultHandler)result.getContext(); replaceMe = true; // (if error/exception then replace thread) if (error == 0) { - rh.completed(ioResult.bytesTransferred()); + rh.completed(ioResult.bytesTransferred(), canInvokeDirect); } else { rh.failed(error, translateErrorToIOException(error)); } @@ -433,5 +445,11 @@ class Iocp extends AsynchronousChannelGroupImpl { static { Util.load(); initIDs(); + + // thread agnostic I/O on Vista/2008 or newer + String osversion = AccessController.doPrivileged( + new GetPropertyAction("os.version")); + String vers[] = osversion.split("\\."); + supportsThreadAgnosticIo = Integer.parseInt(vers[0]) >= 6; } } diff --git a/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java b/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java index e08f460d91946a11dc65cc0706972736f96c9456..0b43ab0d5168c50c93c666cf768820b2e14124a2 100644 --- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java +++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java @@ -146,10 +146,12 @@ public class WindowsAsynchronousFileChannelImpl // waits until all I/O operations have completed ioCache.close(); - // disassociate from port and shutdown thread pool if not default + // disassociate from port iocp.disassociate(completionKey); + + // for the non-default group close the port if (!isDefaultIocp) - iocp.shutdown(); + iocp.detachFromThreadPool(); } @Override @@ -258,14 +260,18 @@ public class WindowsAsynchronousFileChannelImpl } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { // release waiters and invoke completion handler result.setResult(fli); - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -279,16 +285,16 @@ public class WindowsAsynchronousFileChannelImpl } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - public Future lock(long position, - long size, - boolean shared, - A attachment, - CompletionHandler handler) + Future implLock(final long position, + final long size, + final boolean shared, + A attachment, + final CompletionHandler handler) { if (shared && !reading) throw new NonReadableChannelException(); @@ -298,10 +304,11 @@ public class WindowsAsynchronousFileChannelImpl // add to lock table FileLockImpl fli = addToFileLockTable(position, size, shared); if (fli == null) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } // create Future and task that will be invoked to acquire lock @@ -310,13 +317,20 @@ public class WindowsAsynchronousFileChannelImpl LockTask lockTask = new LockTask(position, fli, result); result.setContext(lockTask); - // initiate I/O (can only be done from thread in thread pool) - try { - Invoker.invokeOnThreadInThreadPool(this, lockTask); - } catch (ShutdownChannelGroupException e) { - // rollback - removeFromFileLockTable(fli); - throw e; + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + lockTask.run(); + } else { + boolean executed = false; + try { + Invoker.invokeOnThreadInThreadPool(this, lockTask); + executed = true; + } finally { + if (!executed) { + // rollback + removeFromFileLockTable(fli); + } + } } return result; } @@ -461,14 +475,14 @@ public class WindowsAsynchronousFileChannelImpl releaseBufferIfSubstituted(); // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** * Executed when the I/O has completed */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { updatePosition(bytesTransferred); // return direct buffer to cache if substituted @@ -476,14 +490,18 @@ public class WindowsAsynchronousFileChannelImpl // release waiters and invoke completion handler result.setResult(bytesTransferred); - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override public void failed(int error, IOException x) { // if EOF detected asynchronously then it is reported as error if (error == ERROR_HANDLE_EOF) { - completed(-1); + completed(-1, false); } else { // return direct buffer to cache if substituted releaseBufferIfSubstituted(); @@ -494,16 +512,16 @@ public class WindowsAsynchronousFileChannelImpl } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } } @Override - public Future read(ByteBuffer dst, - long position, - A attachment, - CompletionHandler handler) + Future implRead(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler) { if (!reading) throw new NonReadableChannelException(); @@ -514,10 +532,11 @@ public class WindowsAsynchronousFileChannelImpl // check if channel is closed if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } int pos = dst.position(); @@ -527,10 +546,10 @@ public class WindowsAsynchronousFileChannelImpl // no space remaining if (rem == 0) { - CompletedFuture result = - CompletedFuture.withResult(this, 0, attachment); - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(0); + Invoker.invoke(this, handler, attachment, 0, null); + return null; } // create Future and task that initiates read @@ -539,8 +558,12 @@ public class WindowsAsynchronousFileChannelImpl ReadTask readTask = new ReadTask(dst, pos, rem, position, result); result.setContext(readTask); - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, readTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + readTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, readTask); + } return result; } @@ -639,14 +662,14 @@ public class WindowsAsynchronousFileChannelImpl } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** * Executed when the I/O has completed */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { updatePosition(bytesTransferred); // return direct buffer to cache if substituted @@ -654,7 +677,11 @@ public class WindowsAsynchronousFileChannelImpl // release waiters and invoke completion handler result.setResult(bytesTransferred); - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -668,15 +695,14 @@ public class WindowsAsynchronousFileChannelImpl } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } - @Override - public Future write(ByteBuffer src, - long position, - A attachment, - CompletionHandler handler) + Future implWrite(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler) { if (!writing) throw new NonWritableChannelException(); @@ -685,10 +711,11 @@ public class WindowsAsynchronousFileChannelImpl // check if channel is closed if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } int pos = src.position(); @@ -698,10 +725,10 @@ public class WindowsAsynchronousFileChannelImpl // nothing to write if (rem == 0) { - CompletedFuture result = - CompletedFuture.withResult(this, 0, attachment); - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(0); + Invoker.invoke(this, handler, attachment, 0, null); + return null; } // create Future and task to initiate write @@ -710,8 +737,12 @@ public class WindowsAsynchronousFileChannelImpl WriteTask writeTask = new WriteTask(src, pos, rem, position, result); result.setContext(writeTask); - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, writeTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + writeTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, writeTask); + } return result; } diff --git a/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java b/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java index 8efb10d75e68c9c6873a432fdc1bf9815e72773e..4c85952ac5f248db2c3dff8cc6fab21510e0edef 100644 --- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java +++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java @@ -113,14 +113,14 @@ class WindowsAsynchronousServerSocketChannelImpl /** * Task to initiate accept operation and to handle result. */ - private class AcceptTask implements Runnable, Iocp.ResultHandler { + private class AcceptTask implements Runnable, Iocp.ResultHandler { private final WindowsAsynchronousSocketChannelImpl channel; private final AccessControlContext acc; - private final PendingFuture result; + private final PendingFuture result; AcceptTask(WindowsAsynchronousSocketChannelImpl channel, AccessControlContext acc, - PendingFuture result) + PendingFuture result) { this.channel = channel; this.acc = acc; @@ -222,14 +222,14 @@ class WindowsAsynchronousServerSocketChannelImpl } // invoke completion handler - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(result); } /** * Executed when the I/O has completed */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { try { // connection accept after group has shutdown if (iocp.isShutdown()) { @@ -269,7 +269,7 @@ class WindowsAsynchronousServerSocketChannelImpl } // invoke handler (but not directly) - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(result); } @Override @@ -283,19 +283,20 @@ class WindowsAsynchronousServerSocketChannelImpl } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(result); } } @Override - public Future accept(A attachment, - final CompletionHandler handler) + Future implAccept(Object attachment, + final CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invokeIndirectly(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invokeIndirectly(this, handler, attachment, null, exc); + return null; } if (isAcceptKilled()) throw new RuntimeException("Accept not allowed due to cancellation"); @@ -319,10 +320,10 @@ class WindowsAsynchronousServerSocketChannelImpl end(); } if (ioe != null) { - CompletedFuture result = - CompletedFuture.withFailure(this, ioe, attachment); - Invoker.invokeIndirectly(handler, result); - return result; + if (handler == null) + return CompletedFuture.withFailure(ioe); + Invoker.invokeIndirectly(this, handler, attachment, null, ioe); + return null; } // need calling context when there is security manager as @@ -331,20 +332,21 @@ class WindowsAsynchronousServerSocketChannelImpl AccessControlContext acc = (System.getSecurityManager() == null) ? null : AccessController.getContext(); - PendingFuture result = - new PendingFuture(this, handler, attachment); - AcceptTask task = new AcceptTask(ch, acc, result); + PendingFuture result = + new PendingFuture(this, handler, attachment); + AcceptTask task = new AcceptTask(ch, acc, result); result.setContext(task); // check and set flag to prevent concurrent accepting if (!accepting.compareAndSet(false, true)) throw new AcceptPendingException(); - // initiate accept. As I/O operations are tied to the initiating thread - // then it will only be invoked direcly if this thread is in the thread - // pool. If this thread is not in the thread pool when a task is - // submitted to initiate the accept. - Invoker.invokeOnThreadInThreadPool(this, task); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + task.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, task); + } return result; } diff --git a/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index 5ec0af0468f644eb36e507ac6dd698b940f6a003..80c32ff56dcb7321a62dd2800d68c1dd97dc6090 100644 --- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -250,14 +250,14 @@ class WindowsAsynchronousSocketChannelImpl closeChannel(); result.setFailure(toIOException(exc)); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** * Invoked by handler thread when connection established. */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { Throwable exc = null; try { begin(); @@ -276,7 +276,11 @@ class WindowsAsynchronousSocketChannelImpl result.setFailure(toIOException(exc)); } - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } /** @@ -290,20 +294,21 @@ class WindowsAsynchronousSocketChannelImpl } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - public Future connect(SocketAddress remote, - A attachment, - CompletionHandler handler) + Future implConnect(SocketAddress remote, + A attachment, + CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } InetSocketAddress isa = Net.checkAddress(remote); @@ -337,10 +342,10 @@ class WindowsAsynchronousSocketChannelImpl try { close(); } catch (IOException ignore) { } - CompletedFuture result = CompletedFuture - .withFailure(this, bindException, attachment); - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withFailure(bindException); + Invoker.invoke(this, handler, attachment, null, bindException); + return null; } // setup task @@ -349,8 +354,12 @@ class WindowsAsynchronousSocketChannelImpl ConnectTask task = new ConnectTask(isa, result); result.setContext(task); - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, task); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + task.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, task); + } return result; } @@ -514,7 +523,7 @@ class WindowsAsynchronousSocketChannelImpl } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -522,7 +531,7 @@ class WindowsAsynchronousSocketChannelImpl */ @Override @SuppressWarnings("unchecked") - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { if (bytesTransferred == 0) { bytesTransferred = -1; // EOF } else { @@ -543,7 +552,11 @@ class WindowsAsynchronousSocketChannelImpl result.setResult((V)Integer.valueOf(bytesTransferred)); } } - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -561,7 +574,7 @@ class WindowsAsynchronousSocketChannelImpl enableReading(); result.setFailure(x); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -579,13 +592,14 @@ class WindowsAsynchronousSocketChannelImpl } // invoke handler without any locks - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - Future readImpl(ByteBuffer[] bufs, - boolean scatteringRead, + Future implRead(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, @@ -594,7 +608,14 @@ class WindowsAsynchronousSocketChannelImpl // setup task PendingFuture result = new PendingFuture(this, handler, attachment); - final ReadTask readTask = new ReadTask(bufs, scatteringRead, result); + ByteBuffer[] bufs; + if (isScatteringRead) { + bufs = dsts; + } else { + bufs = new ByteBuffer[1]; + bufs[0] = dst; + } + final ReadTask readTask = new ReadTask(bufs, isScatteringRead, result); result.setContext(readTask); // schedule timeout @@ -607,8 +628,12 @@ class WindowsAsynchronousSocketChannelImpl result.setTimeoutTask(timeoutTask); } - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, readTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + readTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, readTask); + } return result; } @@ -710,7 +735,7 @@ class WindowsAsynchronousSocketChannelImpl } @Override - @SuppressWarnings("unchecked") + //@SuppressWarnings("unchecked") public void run() { long overlapped = 0L; boolean prepared = false; @@ -759,7 +784,7 @@ class WindowsAsynchronousSocketChannelImpl } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -767,7 +792,7 @@ class WindowsAsynchronousSocketChannelImpl */ @Override @SuppressWarnings("unchecked") - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { updateBuffers(bytesTransferred); // return direct buffer to cache if substituted @@ -784,7 +809,11 @@ class WindowsAsynchronousSocketChannelImpl result.setResult((V)Integer.valueOf(bytesTransferred)); } } - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -802,7 +831,7 @@ class WindowsAsynchronousSocketChannelImpl enableWriting(); result.setFailure(x); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -820,13 +849,14 @@ class WindowsAsynchronousSocketChannelImpl } // invoke handler without any locks - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - Future writeImpl(ByteBuffer[] bufs, - boolean gatheringWrite, + Future implWrite(boolean gatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, @@ -835,6 +865,13 @@ class WindowsAsynchronousSocketChannelImpl // setup task PendingFuture result = new PendingFuture(this, handler, attachment); + ByteBuffer[] bufs; + if (gatheringWrite) { + bufs = srcs; + } else { + bufs = new ByteBuffer[1]; + bufs[0] = src; + } final WriteTask writeTask = new WriteTask(bufs, gatheringWrite, result); result.setContext(writeTask); @@ -849,7 +886,12 @@ class WindowsAsynchronousSocketChannelImpl } // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, writeTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + writeTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, writeTask); + } return result; } diff --git a/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java b/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java index 5af9876f33ceb47252a328af719c50cf6e2b60e1..44cdb276de2805d72290b00cc513ee8a82f358c9 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java @@ -46,6 +46,7 @@ class WindowsFileAttributeViews { @Override public WindowsFileAttributes readAttributes() throws IOException { + file.checkRead(); try { return WindowsFileAttributes.get(file, followLinks); } catch (WindowsException x) { diff --git a/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 9a1e0bd1a15b169350459d48a94bd842b9442873..69105a968344f96388fa39e7d45ea2b3fda9bea8 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -246,8 +246,8 @@ class WindowsFileAttributes long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME); long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); - int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? - + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; + int reparseTag = isReparsePoint(fileAttrs) ? + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; return new WindowsFileAttributes(fileAttrs, creationTime, lastAccessTime, @@ -275,7 +275,7 @@ class WindowsFileAttributes int reparseTag = 0; int fileAttrs = unsafe .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); - if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + if (isReparsePoint(fileAttrs)) { int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); try { @@ -311,7 +311,7 @@ class WindowsFileAttributes // just return the attributes int fileAttrs = unsafe .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); - if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + if (!isReparsePoint(fileAttrs)) return fromFileAttributeData(address, 0); } catch (WindowsException x) { if (x.lastError() != ERROR_SHARING_VIOLATION) @@ -358,7 +358,7 @@ class WindowsFileAttributes } /** - * Returns true if the attribtues are of the same file - both files must + * Returns true if the attributes are of the same file - both files must * be open. */ static boolean isSameFile(WindowsFileAttributes attrs1, @@ -370,6 +370,13 @@ class WindowsFileAttributes (attrs1.fileIndexLow == attrs2.fileIndexLow); } + /** + * Returns true if the attributes are of a file with a reparse point. + */ + static boolean isReparsePoint(int attributes) { + return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + } + // package-private int attributes() { return fileAttrs; @@ -420,7 +427,7 @@ class WindowsFileAttributes // package private boolean isReparsePoint() { - return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + return isReparsePoint(fileAttrs); } boolean isDirectoryLink() { diff --git a/src/windows/classes/sun/nio/fs/WindowsFileSystem.java b/src/windows/classes/sun/nio/fs/WindowsFileSystem.java index 54712098b672f852f4903548f15df79fde5914a6..2ad40cb779889bc1a384ca86b936307d77d3812e 100644 --- a/src/windows/classes/sun/nio/fs/WindowsFileSystem.java +++ b/src/windows/classes/sun/nio/fs/WindowsFileSystem.java @@ -283,25 +283,15 @@ class WindowsFileSystem } } - // match in uppercase - StringBuilder sb = new StringBuilder(expr.length()); - for (int i=0; i= 0) { + try { + path = GetFullPathName(path); + } catch (WindowsException x) { + x.rethrowAsIOException(input); + } } // string builder to build up components of path @@ -229,12 +212,15 @@ class WindowsLinkSupport { throw new AssertionError("path type not recognized"); } - // check root directory exists - try { - FirstFile fileData = FindFirstFile(sb.toString() + "*"); - FindClose(fileData.handle()); - } catch (WindowsException x) { - x.rethrowAsIOException(path); + // if the result is only a root component then we simply check it exists + if (start >= path.length()) { + String result = sb.toString(); + try { + GetFileAttributes(result); + } catch (WindowsException x) { + x.rethrowAsIOException(path); + } + return result; } // iterate through each component to get its actual name in the @@ -246,13 +232,28 @@ class WindowsLinkSupport { String search = sb.toString() + path.substring(curr, end); try { FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search)); - try { - sb.append(fileData.name()); - if (next != -1) { - sb.append('\\'); + FindClose(fileData.handle()); + + // if a reparse point is encountered then we must return the + // final path. + if (resolveLinks && + WindowsFileAttributes.isReparsePoint(fileData.attributes())) + { + String result = getFinalPath(input); + if (result == null) { + // Fallback to slow path, usually because there is a sym + // link to a file system that doesn't support sym links. + WindowsPath resolved = resolveAllLinks( + WindowsPath.createFromNormalizedPath(fs, path)); + result = getRealPath(resolved, false); } - } finally { - FindClose(fileData.handle()); + return result; + } + + // add the name to the result + sb.append(fileData.name()); + if (next != -1) { + sb.append('\\'); } } catch (WindowsException e) { e.rethrowAsIOException(path); @@ -342,7 +343,7 @@ class WindowsLinkSupport { /** * Resolve all symbolic-links in a given absolute and normalized path */ - private static String resolveAllLinks(WindowsPath path) + private static WindowsPath resolveAllLinks(WindowsPath path) throws IOException { assert path.isAbsolute(); @@ -401,7 +402,7 @@ class WindowsLinkSupport { } } - return path.toString(); + return path; } /** diff --git a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java index a116bf8119083d024b4c2ad3432fce234c0ae9df..0ad876755be6540cea97cfef2508ef92a8d6920b 100644 --- a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java +++ b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -180,10 +180,12 @@ class WindowsNativeDispatcher { static class FirstFile { private long handle; private String name; + private int attributes; private FirstFile() { } public long handle() { return handle; } public String name() { return name; } + public int attributes() { return attributes; } } private static native void FindFirstFile0(long lpFileName, FirstFile obj) throws WindowsException; diff --git a/src/windows/native/java/io/WinNTFileSystem_md.c b/src/windows/native/java/io/WinNTFileSystem_md.c index f4cc691115b1be94e027188a15b831debdd9524b..30d0d371ce417a84aeec2d30c89b7321d37c592f 100644 --- a/src/windows/native/java/io/WinNTFileSystem_md.c +++ b/src/windows/native/java/io/WinNTFileSystem_md.c @@ -51,13 +51,25 @@ static struct { jfieldID path; } ids; +/** + * GetFinalPathNameByHandle is available on Windows Vista and newer + */ +typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); +static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; + JNIEXPORT void JNICALL Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls) { + HANDLE handle; jclass fileClass = (*env)->FindClass(env, "java/io/File"); if (!fileClass) return; ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;"); + handle = LoadLibrary("kernel32"); + if (handle != NULL) { + GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc) + GetProcAddress(handle, "GetFinalPathNameByHandleW"); + } } /* -- Path operations -- */ @@ -65,6 +77,138 @@ Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls) extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len); extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len); +/** + * Retrieves the fully resolved (final) path for the given path or NULL + * if the function fails. + */ +static WCHAR* getFinalPath(const WCHAR *path) +{ + HANDLE h; + WCHAR *result; + DWORD error; + + /* Need Windows Vista or newer to get the final path */ + if (GetFinalPathNameByHandle_func == NULL) + return NULL; + + h = CreateFileW(path, + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (h == INVALID_HANDLE_VALUE) + return NULL; + + /** + * Allocate a buffer for the resolved path. For a long path we may need + * to allocate a larger buffer. + */ + result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR)); + if (result != NULL) { + DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0); + if (len >= MAX_PATH) { + /* retry with a buffer of the right size */ + result = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR)); + if (result != NULL) { + len = (*GetFinalPathNameByHandle_func)(h, result, len, 0); + } else { + len = 0; + } + } + if (len > 0) { + /** + * Strip prefix (should be \\?\ or \\?\UNC) + */ + if (result[0] == L'\\' && result[1] == L'\\' && + result[2] == L'?' && result[3] == L'\\') + { + int isUnc = (result[4] == L'U' && + result[5] == L'N' && + result[6] == L'C'); + int prefixLen = (isUnc) ? 7 : 4; + /* actual result length (includes terminator) */ + int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1; + + /* copy result without prefix into new buffer */ + WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR)); + if (tmp == NULL) { + len = 0; + } else { + WCHAR *p = result; + p += prefixLen; + if (isUnc) { + WCHAR *p2 = tmp; + p2[0] = L'\\'; + p2++; + wcscpy(p2, p); + } else { + wcscpy(tmp, p); + } + free(result); + result = tmp; + } + } + } + + /* unable to get final path */ + if (len == 0 && result != NULL) { + free(result); + result = NULL; + } + } + + error = GetLastError(); + if (CloseHandle(h)) + SetLastError(error); + return result; +} + +/** + * Retrieves file information for the specified file. If the file is + * symbolic link then the information on fully resolved target is + * returned. + */ +static BOOL getFileInformation(const WCHAR *path, + BY_HANDLE_FILE_INFORMATION *finfo) +{ + BOOL result; + DWORD error; + HANDLE h = CreateFileW(path, + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (h == INVALID_HANDLE_VALUE) + return FALSE; + result = GetFileInformationByHandle(h, finfo); + error = GetLastError(); + if (CloseHandle(h)) + SetLastError(error); + return result; +} + +/** + * If the given attributes are the attributes of a reparse point, then + * read and return the attributes of the final target. + */ +DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a) +{ + if ((a != INVALID_FILE_ATTRIBUTES) && + ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) + { + BY_HANDLE_FILE_INFORMATION finfo; + BOOL res = getFileInformation(path, &finfo); + a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES; + } + return a; +} + JNIEXPORT jstring JNICALL Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this, jstring pathname) @@ -202,12 +346,15 @@ Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this, return rv; if (!isReservedDeviceNameW(pathbuf)) { if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) { - rv = (java_io_FileSystem_BA_EXISTS - | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - ? java_io_FileSystem_BA_DIRECTORY - : java_io_FileSystem_BA_REGULAR) - | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - ? java_io_FileSystem_BA_HIDDEN : 0)); + DWORD a = getFinalAttributesIfReparsePoint(pathbuf, wfad.dwFileAttributes); + if (a != INVALID_FILE_ATTRIBUTES) { + rv = (java_io_FileSystem_BA_EXISTS + | ((a & FILE_ATTRIBUTE_DIRECTORY) + ? java_io_FileSystem_BA_DIRECTORY + : java_io_FileSystem_BA_REGULAR) + | ((a & FILE_ATTRIBUTE_HIDDEN) + ? java_io_FileSystem_BA_HIDDEN : 0)); + } } else { /* pagefile.sys is a special case */ if (GetLastError() == ERROR_SHARING_VIOLATION) { rv = java_io_FileSystem_BA_EXISTS; @@ -234,6 +381,7 @@ JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this, if (pathbuf == NULL) return JNI_FALSE; attr = GetFileAttributesW(pathbuf); + attr = getFinalAttributesIfReparsePoint(pathbuf, attr); free(pathbuf); if (attr == INVALID_FILE_ATTRIBUTES) return JNI_FALSE; @@ -272,6 +420,20 @@ Java_java_io_WinNTFileSystem_setPermission(JNIEnv *env, jobject this, if (pathbuf == NULL) return JNI_FALSE; a = GetFileAttributesW(pathbuf); + + /* if reparse point, get final target */ + if ((a != INVALID_FILE_ATTRIBUTES) && + ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) + { + WCHAR *fp = getFinalPath(pathbuf); + if (fp == NULL) { + a = INVALID_FILE_ATTRIBUTES; + } else { + free(pathbuf); + pathbuf = fp; + a = GetFileAttributesW(pathbuf); + } + } if (a != INVALID_FILE_ATTRIBUTES) { if (enable) a = a & ~FILE_ATTRIBUTE_READONLY; @@ -305,7 +467,7 @@ Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this, /* Open existing or fail */ OPEN_EXISTING, /* Backup semantics for directories */ - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + FILE_FLAG_BACKUP_SEMANTICS, /* No template file */ NULL); if (h != INVALID_HANDLE_VALUE) { @@ -332,7 +494,16 @@ Java_java_io_WinNTFileSystem_getLength(JNIEnv *env, jobject this, jobject file) if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) { - rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow; + if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) { + rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow; + } else { + /* file is a reparse point so read attributes of final target */ + BY_HANDLE_FILE_INFORMATION finfo; + if (getFileInformation(pathbuf, &finfo)) { + rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) + + finfo.nFileSizeLow; + } + } } else { if (GetLastError() == ERROR_SHARING_VIOLATION) { /* The error is "share violation", which means the file/dir @@ -360,31 +531,29 @@ Java_java_io_WinNTFileSystem_createFileExclusively(JNIEnv *env, jclass cls, if (pathbuf == NULL) return JNI_FALSE; h = CreateFileW( - pathbuf, /* Wide char path name */ - GENERIC_READ | GENERIC_WRITE, /* Read and write permission */ + pathbuf, /* Wide char path name */ + GENERIC_READ | GENERIC_WRITE, /* Read and write permission */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */ - NULL, /* Security attributes */ - CREATE_NEW, /* creation disposition */ - FILE_ATTRIBUTE_NORMAL, /* flags and attributes */ + NULL, /* Security attributes */ + CREATE_NEW, /* creation disposition */ + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */ NULL); if (h == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) { - - // If a directory by the named path already exists, - // return false (behavior of solaris and linux) instead of - // throwing an exception - DWORD fattr = GetFileAttributesW(pathbuf); - if ((fattr == INVALID_FILE_ATTRIBUTES) || - (fattr & ~FILE_ATTRIBUTE_DIRECTORY)) { + // return false rather than throwing an exception when there is + // an existing file. + DWORD a = GetFileAttributesW(pathbuf); + if (a == INVALID_FILE_ATTRIBUTES) { SetLastError(error); JNU_ThrowIOExceptionWithLastError(env, "Could not open file"); } } free(pathbuf); return JNI_FALSE; - } + } free(pathbuf); CloseHandle(h); return JNI_TRUE; @@ -396,9 +565,9 @@ removeFileOrDirectory(const jchar *path) /* Returns 0 on success */ DWORD a; - SetFileAttributesW(path, 0); + SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL); a = GetFileAttributesW(path); - if (a == ((DWORD)-1)) { + if (a == INVALID_FILE_ATTRIBUTES) { return 1; } else if (a & FILE_ATTRIBUTE_DIRECTORY) { return !RemoveDirectoryW(path); @@ -578,8 +747,13 @@ Java_java_io_WinNTFileSystem_setLastModifiedTime(JNIEnv *env, jobject this, HANDLE h; if (pathbuf == NULL) return JNI_FALSE; - h = CreateFileW(pathbuf, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); + h = CreateFileW(pathbuf, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0); if (h != INVALID_HANDLE_VALUE) { LARGE_INTEGER modTime; FILETIME t; @@ -607,6 +781,21 @@ Java_java_io_WinNTFileSystem_setReadOnly(JNIEnv *env, jobject this, if (pathbuf == NULL) return JNI_FALSE; a = GetFileAttributesW(pathbuf); + + /* if reparse point, get final target */ + if ((a != INVALID_FILE_ATTRIBUTES) && + ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) + { + WCHAR *fp = getFinalPath(pathbuf); + if (fp == NULL) { + a = INVALID_FILE_ATTRIBUTES; + } else { + free(pathbuf); + pathbuf = fp; + a = GetFileAttributesW(pathbuf); + } + } + if (a != INVALID_FILE_ATTRIBUTES) { if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY)) rv = JNI_TRUE; diff --git a/src/windows/native/sun/nio/ch/Iocp.c b/src/windows/native/sun/nio/ch/Iocp.c index 9568189ee6be866ce60dc9053346bcd15be16108..e80cd91205cb66495f6061d1099459d46255dcc0 100644 --- a/src/windows/native/sun/nio/ch/Iocp.c +++ b/src/windows/native/sun/nio/ch/Iocp.c @@ -58,6 +58,16 @@ Java_sun_nio_ch_Iocp_initIDs(JNIEnv* env, jclass this) completionStatus_overlapped = (*env)->GetFieldID(env, clazz, "overlapped", "J"); } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Iocp_osMajorVersion(JNIEnv* env, jclass this) +{ + OSVERSIONINFOEX ver; + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx((OSVERSIONINFO *) &ver); + return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? + (jint)(ver.dwMajorVersion) : (jint)0; +} + JNIEXPORT jlong JNICALL Java_sun_nio_ch_Iocp_createIoCompletionPort(JNIEnv* env, jclass this, jlong handle, jlong existingPort, jint completionKey, jint concurrency) diff --git a/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c b/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c index d5195c4f7b3708aabf2831c11e48d44572c88736..8e07bde64b6a3cecbe21b8ad32119e217dd4e0d2 100644 --- a/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c +++ b/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c @@ -48,6 +48,7 @@ */ static jfieldID findFirst_handle; static jfieldID findFirst_name; +static jfieldID findFirst_attributes; static jfieldID findStream_handle; static jfieldID findStream_name; @@ -134,6 +135,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) } findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); + findFirst_attributes = (*env)->GetFieldID(env, clazz, "attributes", "I"); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream"); if (clazz == NULL) { @@ -371,6 +373,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0(JNIEnv* env, jclass this, return; (*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle)); (*env)->SetObjectField(env, obj, findFirst_name, name); + (*env)->SetIntField(env, obj, findFirst_attributes, data.dwFileAttributes); } else { throwWindowsException(env, GetLastError()); } @@ -387,7 +390,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this, if (handle == INVALID_HANDLE_VALUE) { throwWindowsException(env, GetLastError()); } - return ptr_to_jlong(handle); + return ptr_to_jlong(handle); } JNIEXPORT jstring JNICALL diff --git a/test/com/sun/security/auth/callback/TextCallbackHandler/Password.java b/test/com/sun/security/auth/callback/TextCallbackHandler/Password.java new file mode 100644 index 0000000000000000000000000000000000000000..61330616f06f1506df44add7df5a3490722990b8 --- /dev/null +++ b/test/com/sun/security/auth/callback/TextCallbackHandler/Password.java @@ -0,0 +1,47 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6825240 + * @summary Password.readPassword() echos the input when System.Console is null + * @ignore run these by hand + */ + +import com.sun.security.auth.callback.TextCallbackHandler; +import javax.security.auth.callback.*; + +public class Password { + public static void main(String args[]) throws Exception { + TextCallbackHandler h = new TextCallbackHandler(); + PasswordCallback nc = new PasswordCallback("Invisible: ", false); + PasswordCallback nc2 = new PasswordCallback("Visible: ", true); + + System.out.println("Two passwords will be prompted for. The first one " + + "should have echo off, the second one on. Otherwise, this test fails"); + Callback[] callbacks = { nc, nc2 }; + h.handle(callbacks); + System.out.println("You input " + new String(nc.getPassword()) + + " and " + new String(nc2.getPassword())); + } +} diff --git a/test/java/io/File/SymLinks.java b/test/java/io/File/SymLinks.java new file mode 100644 index 0000000000000000000000000000000000000000..748f2086bd17dc5352c330f46fafb78f56291e53 --- /dev/null +++ b/test/java/io/File/SymLinks.java @@ -0,0 +1,380 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6595866 + * @summary Test java.io.File operations with sym links + */ + +import java.io.*; +import java.nio.file.Path; +import java.nio.file.attribute.*; +import static java.nio.file.LinkOption.*; + +public class SymLinks { + final static PrintStream out = System.out; + + final static File top = new File(System.getProperty("test.dir", ".")); + + // files used by the test + + final static File file = new File(top, "foofile"); + final static File link2file = new File(top, "link2file"); + final static File link2link2file = new File(top, "link2link2file"); + + final static File dir = new File(top, "foodir"); + final static File link2dir = new File(top, "link2dir"); + final static File link2link2dir = new File(top, "link2link2dir"); + + final static File link2nobody = new File(top, "link2nobody"); + final static File link2link2nobody = new File(top, "link2link2nobody"); + + /** + * Setup files, directories, and sym links used by test. + */ + static void setup() throws IOException { + // link2link2file -> link2file -> foofile + FileOutputStream fos = new FileOutputStream(file); + try { + fos.write(new byte[16*1024]); + } finally { + fos.close(); + } + mklink(link2file, file); + mklink(link2link2file, link2file); + + // link2link2dir -> link2dir -> dir + assertTrue(dir.mkdir()); + mklink(link2dir, dir); + mklink(link2link2dir, link2dir); + + // link2link2nobody -> link2nobody -> + mklink(link2nobody, new File(top, "DoesNotExist")); + mklink(link2link2nobody, link2nobody); + } + + /** + * Remove files, directories, and sym links used by test. + */ + static void cleanup() throws IOException { + if (file != null) + file.delete(); + if (link2file != null) + link2file.toPath().deleteIfExists(); + if (link2link2file != null) + link2link2file.toPath().deleteIfExists(); + if (dir != null) + dir.delete(); + if (link2dir != null) + link2dir.toPath().deleteIfExists(); + if (link2link2dir != null) + link2link2dir.toPath().deleteIfExists(); + if (link2nobody != null) + link2nobody.toPath().deleteIfExists(); + if (link2link2nobody != null) + link2link2nobody.toPath().deleteIfExists(); + } + + /** + * Creates a sym link source->target + */ + static void mklink(File source, File target) throws IOException { + source.toPath().createSymbolicLink(target.toPath()); + } + + /** + * Returns true if the "link" exists and is a sym link. + */ + static boolean isSymLink(File link) { + try { + BasicFileAttributes attrs = + Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); + return attrs.isSymbolicLink(); + } catch (IOException x) { + return false; + } + } + + /** + * Returns the last modified time of a sym link. + */ + static long lastModifiedOfSymLink(File link) throws IOException { + BasicFileAttributes attrs = + Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); + assertTrue(attrs.isSymbolicLink()); + return attrs.lastModifiedTime().toMillis(); + } + + /** + * Returns true if sym links are supported on the file system where + * "dir" exists. + */ + static boolean supportsSymLinks(File dir) { + Path link = dir.toPath().resolve("link"); + Path target = dir.toPath().resolve("target"); + try { + link.createSymbolicLink(target); + link.delete(); + return true; + } catch (UnsupportedOperationException x) { + return false; + } catch (IOException x) { + return false; + } + } + + static void assertTrue(boolean v) { + if (!v) throw new RuntimeException("Test failed"); + } + + static void assertFalse(boolean v) { + assertTrue(!v); + } + + static void header(String h) { + out.println(); + out.println(); + out.println("-- " + h + " --"); + } + + /** + * Tests go here. + */ + static void go() throws IOException { + + // check setup + assertTrue(file.isFile()); + assertTrue(isSymLink(link2file)); + assertTrue(isSymLink(link2link2file)); + assertTrue(dir.isDirectory()); + assertTrue(isSymLink(link2dir)); + assertTrue(isSymLink(link2link2dir)); + assertTrue(isSymLink(link2nobody)); + assertTrue(isSymLink(link2link2nobody)); + + header("createNewFile"); + + assertFalse(file.createNewFile()); + assertFalse(link2file.createNewFile()); + assertFalse(link2link2file.createNewFile()); + assertFalse(dir.createNewFile()); + assertFalse(link2dir.createNewFile()); + assertFalse(link2link2dir.createNewFile()); + assertFalse(link2nobody.createNewFile()); + assertFalse(link2link2nobody.createNewFile()); + + header("mkdir"); + + assertFalse(file.mkdir()); + assertFalse(link2file.mkdir()); + assertFalse(link2link2file.mkdir()); + assertFalse(dir.mkdir()); + assertFalse(link2dir.mkdir()); + assertFalse(link2link2dir.mkdir()); + assertFalse(link2nobody.mkdir()); + assertFalse(link2link2nobody.mkdir()); + + header("delete"); + + File link = new File(top, "mylink"); + try { + mklink(link, file); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(file.exists()); + + mklink(link, link2file); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(link2file.exists()); + + mklink(link, dir); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(dir.exists()); + + mklink(link, link2dir); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(link2dir.exists()); + + mklink(link, link2nobody); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(isSymLink(link2nobody)); + + } finally { + link.toPath().deleteIfExists(); + } + + header("renameTo"); + + File newlink = new File(top, "newlink"); + assertTrue(link2file.renameTo(newlink)); + try { + assertTrue(file.exists()); + assertTrue(isSymLink(newlink)); + assertTrue(!isSymLink(link2file)); + } finally { + newlink.renameTo(link2file); // restore link + } + + assertTrue(link2dir.renameTo(newlink)); + try { + assertTrue(dir.exists()); + assertTrue(isSymLink(newlink)); + assertTrue(!isSymLink(link2dir)); + } finally { + newlink.renameTo(link2dir); // restore link + } + + header("list"); + + final String name = "entry"; + File entry = new File(dir, name); + try { + assertTrue(dir.list().length == 0); // directory should be empty + assertTrue(link2dir.list().length == 0); + assertTrue(link2link2dir.list().length == 0); + + assertTrue(entry.createNewFile()); + assertTrue(dir.list().length == 1); + assertTrue(dir.list()[0].equals(name)); + + // access directory by following links + assertTrue(link2dir.list().length == 1); + assertTrue(link2dir.list()[0].equals(name)); + assertTrue(link2link2dir.list().length == 1); + assertTrue(link2link2dir.list()[0].equals(name)); + + // files that are not directories + assertTrue(link2file.list() == null); + assertTrue(link2nobody.list() == null); + + } finally { + entry.delete(); + } + + header("isXXX"); + + assertTrue(file.isFile()); + assertTrue(link2file.isFile()); + assertTrue(link2link2file.isFile()); + + assertTrue(dir.isDirectory()); + assertTrue(link2dir.isDirectory()); + assertTrue(link2link2dir.isDirectory()); + + // on Windows we test with the DOS hidden attribute set + if (System.getProperty("os.name").startsWith("Windows")) { + DosFileAttributeView view = file.toPath() + .getFileAttributeView(DosFileAttributeView.class); + view.setHidden(true); + try { + assertTrue(file.isHidden()); + assertTrue(link2file.isHidden()); + assertTrue(link2link2file.isHidden()); + } finally { + view.setHidden(false); + } + assertFalse(file.isHidden()); + assertFalse(link2file.isHidden()); + assertFalse(link2link2file.isHidden()); + } + + header("length"); + + long len = file.length(); + assertTrue(len > 0L); + // these tests should follow links + assertTrue(link2file.length() == len); + assertTrue(link2link2file.length() == len); + assertTrue(link2nobody.length() == 0L); + + header("lastModified / setLastModified"); + + // need time to diff between link and file + long origLastModified = file.lastModified(); + assertTrue(origLastModified != 0L); + try { Thread.sleep(2000); } catch (InterruptedException x) { } + file.setLastModified(System.currentTimeMillis()); + + long lastModified = file.lastModified(); + assertTrue(lastModified != origLastModified); + assertTrue(lastModifiedOfSymLink(link2file) != lastModified); + assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified); + assertTrue(link2file.lastModified() == lastModified); + assertTrue(link2link2file.lastModified() == lastModified); + assertTrue(link2nobody.lastModified() == 0L); + + origLastModified = dir.lastModified(); + assertTrue(origLastModified != 0L); + dir.setLastModified(0L); + assertTrue(dir.lastModified() == 0L); + assertTrue(link2dir.lastModified() == 0L); + assertTrue(link2link2dir.lastModified() == 0L); + dir.setLastModified(origLastModified); + + header("setXXX / canXXX"); + + assertTrue(file.canRead()); + assertTrue(file.canWrite()); + assertTrue(link2file.canRead()); + assertTrue(link2file.canWrite()); + assertTrue(link2link2file.canRead()); + assertTrue(link2link2file.canWrite()); + + if (file.setReadOnly()) { + assertFalse(file.canWrite()); + assertFalse(link2file.canWrite()); + assertFalse(link2link2file.canWrite()); + + assertTrue(file.setWritable(true)); // make writable + assertTrue(file.canWrite()); + assertTrue(link2file.canWrite()); + assertTrue(link2link2file.canWrite()); + + assertTrue(link2file.setReadOnly()); // make read only + assertFalse(file.canWrite()); + assertFalse(link2file.canWrite()); + assertFalse(link2link2file.canWrite()); + + assertTrue(link2link2file.setWritable(true)); // make writable + assertTrue(file.canWrite()); + assertTrue(link2file.canWrite()); + assertTrue(link2link2file.canWrite()); + } + } + + public static void main(String[] args) throws IOException { + if (supportsSymLinks(top)) { + try { + setup(); + go(); + } finally { + cleanup(); + } + } + } + +} diff --git a/test/java/lang/String/Split.java b/test/java/lang/String/Split.java index b4ab5fb4c54fa2a259fa18a149048be29ee4f8d9..fa03eb397b98f6ae34db388d91d7e45296ea0ab3 100644 --- a/test/java/lang/String/Split.java +++ b/test/java/lang/String/Split.java @@ -23,14 +23,18 @@ /** * @test + * @bug 6840246 * @summary test String.split() */ +import java.util.Arrays; +import java.util.Random; import java.util.regex.*; public class Split { public static void main(String[] args) throws Exception { String source = "0123456789"; + for (int limit=-2; limit<3; limit++) { for (int x=0; x<10; x++) { String[] result = source.split(Integer.toString(x), limit); @@ -80,5 +84,48 @@ public class Split { throw new RuntimeException("String.split failure 8"); if (!result[0].equals(source)) throw new RuntimeException("String.split failure 9"); + + // check fastpath of String.split() + source = "0123456789abcdefgABCDEFG"; + Random r = new Random(); + + for (boolean doEscape: new boolean[] {false, true}) { + for (int cp = 0; cp < 0x11000; cp++) { + Pattern p = null; + String regex = new String(Character.toChars(cp)); + if (doEscape) + regex = "\\" + regex; + try { + p = Pattern.compile(regex); + } catch (PatternSyntaxException pse) { + // illegal syntax + try { + "abc".split(regex); + } catch (PatternSyntaxException pse0) { + continue; + } + throw new RuntimeException("String.split failure 11"); + } + int off = r.nextInt(source.length()); + String[] srcStrs = new String[] { + "", + source, + regex + source, + source + regex, + source.substring(0, 3) + + regex + source.substring(3, 9) + + regex + source.substring(9, 15) + + regex + source.substring(15), + source.substring(0, off) + regex + source.substring(off) + }; + for (String src: srcStrs) { + for (int limit=-2; limit<3; limit++) { + if (!Arrays.equals(src.split(regex, limit), + p.split(src, limit))) + throw new RuntimeException("String.split failure 12"); + } + } + } + } } } diff --git a/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java b/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java index 4478c9bd851c203400322696f99d25e7b5e55860..3988ab8c568d5855562fb865e4ae49bbff10f782 100644 --- a/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java +++ b/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup */ @@ -50,8 +50,6 @@ public class GroupOfOne { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); @@ -97,9 +95,6 @@ public class GroupOfOne { System.out.println("Read failed (expected)"); latch.countDown(); } - public void cancelled(Void att) { - throw new RuntimeException(); - } }); // close channel or shutdown group @@ -122,9 +117,6 @@ public class GroupOfOne { public void failed(Throwable exc, Void att) { throw new RuntimeException(exc); } - public void cancelled(Void att) { - throw new RuntimeException(); - } }); latch.await(); diff --git a/test/java/nio/channels/AsynchronousChannelGroup/Identity.java b/test/java/nio/channels/AsynchronousChannelGroup/Identity.java index 6214df2e1f5039d60562af86510fbfb03e8db523..6756187ce006cf4491be137be48f77f74ee49471 100644 --- a/test/java/nio/channels/AsynchronousChannelGroup/Identity.java +++ b/test/java/nio/channels/AsynchronousChannelGroup/Identity.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup */ @@ -90,14 +90,10 @@ public class Identity { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port); @@ -141,9 +137,6 @@ public class Identity { public void failed(Throwable exc, Integer groupId) { fail(exc.getMessage()); } - public void cancelled(Integer groupId) { - fail("I/O operation was cancelled"); - } }); // wait until diff --git a/test/java/nio/channels/AsynchronousChannelGroup/Restart.java b/test/java/nio/channels/AsynchronousChannelGroup/Restart.java index f2132270e50b776a4959df2f1f23684a81deab60..1645246efda872a26262871991182eff4cbb975b 100644 --- a/test/java/nio/channels/AsynchronousChannelGroup/Restart.java +++ b/test/java/nio/channels/AsynchronousChannelGroup/Restart.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup * @build Restart * @run main/othervm -XX:-UseVMInterruptibleIO Restart @@ -111,8 +111,6 @@ public class Restart { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // establish loopback connection which should cause completion diff --git a/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java b/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java index f77f2fc3c2d95565fbac2101c4c948878eb64660..7b947d949e68f0868baa69cf1b21842d77f2483f 100644 --- a/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java +++ b/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup */ @@ -52,8 +52,6 @@ public class Unbounded { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); System.out.println("Listener created."); @@ -97,8 +95,6 @@ public class Unbounded { } public void failed(Throwable exc, AsynchronousSocketChannel ch) { } - public void cancelled(AsynchronousSocketChannel ch) { - } }); } System.out.println("All read operations outstanding."); diff --git a/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java b/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java index f90800f392dcc32ba9030e52f988c709657336ad..9c390105716dde6ddd6736c3437abf8c79052aa1 100644 --- a/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java +++ b/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4527345 + * @bug 4527345 6842687 * @summary Unit test for AsynchronousDatagramChannel */ @@ -72,8 +72,6 @@ public class Basic { } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); Thread.sleep(2000); sender.send(ByteBuffer.wrap(msg), sa); @@ -88,8 +86,6 @@ public class Basic { public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); Throwable result; while ((result = exception.get()) == null) { @@ -107,8 +103,6 @@ public class Basic { public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); ch.close(); while ((result = exception.get()) == null) { @@ -162,8 +156,6 @@ public class Basic { } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); Thread.sleep(2000); sender.send(ByteBuffer.wrap(msg), sa); @@ -178,8 +170,6 @@ public class Basic { public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); Throwable result; while ((result = exception.get()) == null) { @@ -197,8 +187,6 @@ public class Basic { public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); ch.close(); while ((result = exception.get()) == null) { @@ -246,8 +234,6 @@ public class Basic { } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); l2.await(5, TimeUnit.SECONDS); @@ -272,8 +258,6 @@ public class Basic { throw new RuntimeException(exc); } } - public void cancelled(Void att) { - } }); l3.await(5, TimeUnit.SECONDS); @@ -323,8 +307,6 @@ public class Basic { } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); l2.await(5, TimeUnit.SECONDS); @@ -340,7 +322,7 @@ public class Basic { reader.close(); } - static void cancelAndCheck(Future result, CountDownLatch latch) + static void cancelAndCheck(Future result) throws InterruptedException { boolean cancelled = result.cancel(false); @@ -356,37 +338,22 @@ public class Basic { } catch (ExecutionException e) { throw new RuntimeException("Should not fail"); } - - // make sure that completion handler is invoked - latch.await(); } // basic cancel tests static void doCancelTests() throws Exception { InetAddress lh = InetAddress.getLocalHost(); - // timed and non-timed receive + // receive for (int i=0; i<2; i++) { AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0)); - final CountDownLatch latch = new CountDownLatch(1); - long timeout = (i == 0) ? 0L : 60L; - Future remote = ch - .receive(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, (Void)null, - new CompletionHandler() { - public void completed(SocketAddress source, Void att) { - } - public void failed (Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); - cancelAndCheck(remote, latch); + Future remote = ch.receive(ByteBuffer.allocate(100)); + cancelAndCheck(remote); ch.close(); } - // timed and non-timed read + // read for (int i=0; i<2; i++) { AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0)); @@ -394,18 +361,8 @@ public class Basic { ((InetSocketAddress)(ch.getLocalAddress())).getPort())); final CountDownLatch latch = new CountDownLatch(1); long timeout = (i == 0) ? 0L : 60L; - Future result = ch - .read(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, (Void)null, - new CompletionHandler() { - public void completed(Integer bytesRead, Void att) { - } - public void failed (Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); - cancelAndCheck(result, latch); + Future result = ch.read(ByteBuffer.allocate(100)); + cancelAndCheck(result); ch.close(); } } diff --git a/test/java/nio/channels/AsynchronousFileChannel/Basic.java b/test/java/nio/channels/AsynchronousFileChannel/Basic.java index 92241536642d06e4e166c623b24f2aad147651b0..75bd1348ef59d0e9bd14d9f1a6ab2fe3aa396694 100644 --- a/test/java/nio/channels/AsynchronousFileChannel/Basic.java +++ b/test/java/nio/channels/AsynchronousFileChannel/Basic.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 6822643 6830721 + * @bug 4607272 6822643 6830721 6842687 * @summary Unit test for AsynchronousFileChannel */ @@ -195,8 +195,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); throw new RuntimeException("OverlappingFileLockException expected"); } catch (OverlappingFileLockException x) { @@ -229,8 +227,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // wait for handler to complete @@ -318,8 +314,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); await(latch); @@ -338,7 +332,40 @@ public class Basic { } } finally { ch.close(); + executor.shutdown(); + } + } + + + // test sharing a thread pool between many channels + ExecutorService executor = Executors + .newFixedThreadPool(1+rand.nextInt(10), threadFactory); + final int n = 50 + rand.nextInt(50); + AsynchronousFileChannel[] channels = new AsynchronousFileChannel[n]; + try { + for (int i=0; i opts = EnumSet.of(WRITE); + channels[i] = AsynchronousFileChannel.open(file, opts, executor); + final CountDownLatch latch = new CountDownLatch(1); + channels[i].write(genBuffer(), 0L, (Void)null, new CompletionHandler() { + public void completed(Integer result, Void att) { + latch.countDown(); + } + public void failed(Throwable exc, Void att) { + } + }); + await(latch); + + // close ~half the channels + if (rand.nextBoolean()) + channels[i].close(); + } + } finally { + // close remaining channels + for (int i=0; i res = ch.write(genBuffer(), 0L, (Void)null, - new CompletionHandler() { - public void completed(Integer result, Void att) { - } - public void failed(Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); + Future res = ch.write(genBuffer(), 0L); // cancel operation boolean cancelled = res.cancel(mayInterruptIfRunning); @@ -456,10 +473,6 @@ public class Basic { throw new RuntimeException(x); } - // check that cancelled method is invoked - if (cancelled) - await(latch); - ch.close(); } } @@ -547,8 +560,6 @@ public class Basic { } public void failed(Throwable exc, Long position) { } - public void cancelled(Long position) { - } }); // wait for writes to complete @@ -574,8 +585,6 @@ public class Basic { } public void failed(Throwable exc, Long position) { } - public void cancelled(Long position) { - } }); // wait for reads to complete diff --git a/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java b/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java index 9f9025dd232bedaee786d8efdb21bfbf03f216f4..610124d206134bd3114daea23ac19ceefcbcc9a1 100644 --- a/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java +++ b/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for java.nio.channels.AsynchronousFileChannel * @build CustomThreadPool MyThreadFactory * @run main/othervm -Djava.nio.channels.DefaultThreadPool.threadFactory=MyThreadFactory CustomThreadPool @@ -51,8 +51,6 @@ public class CustomThreadPool { } public void failed(Throwable exc, AtomicReference invoker) { } - public void cancelled(AtomicReference invoker) { - } }); Thread t; while ((t = invoker.get()) == null) { diff --git a/test/java/nio/channels/AsynchronousFileChannel/Lock.java b/test/java/nio/channels/AsynchronousFileChannel/Lock.java index f8b55cc44f89cb5d44d1639a2051034015a0c954..2b41c86766fa340988d9aeed6649318b49828379 100644 --- a/test/java/nio/channels/AsynchronousFileChannel/Lock.java +++ b/test/java/nio/channels/AsynchronousFileChannel/Lock.java @@ -23,7 +23,7 @@ /* @test - * @bug 4607272 6814948 + * @bug 4607272 6814948 6842687 * @summary Unit test for AsynchronousFileChannel#lock method */ @@ -97,7 +97,7 @@ public class Lock { slave.lock(0, 10, false); // this VM acquires lock on non-overlapping range - fl = ch.lock(10, 10, false, null, null).get(); + fl = ch.lock(10, 10, false).get(); fl.release(); // done diff --git a/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java b/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java index e648b78a911ad4bbd368b289ec53af001aaf9cfc..3ff2151fed7f52d44168701a2e43dcb29c87488c 100644 --- a/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java +++ b/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousServerSocketChannel * @run main/timeout=180 Basic */ @@ -104,8 +104,6 @@ public class Basic { public void failed(Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); // check AcceptPendingException diff --git a/test/java/nio/channels/AsynchronousSocketChannel/Basic.java b/test/java/nio/channels/AsynchronousSocketChannel/Basic.java index 3c04635312ba94b554f808438d83baab93c8c2b4..88c4c16e2cdf47f29c5ead4f7c325af427dda08e 100644 --- a/test/java/nio/channels/AsynchronousSocketChannel/Basic.java +++ b/test/java/nio/channels/AsynchronousSocketChannel/Basic.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousSocketChannel * @run main/timeout=600 Basic */ @@ -187,8 +187,6 @@ public class Basic { public void failed(Throwable exc, Void att) { connectException.set(exc); } - public void cancelled(Void att) { - } }); while (connectException.get() == null) { Thread.sleep(100); @@ -289,8 +287,6 @@ public class Basic { public void failed(Throwable x, AsynchronousSocketChannel ch) { writeException.set(x); } - public void cancelled(AsynchronousSocketChannel ch) { - } }); // give time for socket buffer to fill up. @@ -330,18 +326,8 @@ public class Basic { SocketChannel peer = server.accept(); // start read operation - final CountDownLatch latch = new CountDownLatch(1); ByteBuffer buf = ByteBuffer.allocate(1); - Future res = ch.read(buf, (Void)null, - new CompletionHandler() { - public void completed(Integer result, Void att) { - } - public void failed(Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); + Future res = ch.read(buf); // cancel operation boolean cancelled = res.cancel(mayInterruptIfRunning); @@ -362,8 +348,11 @@ public class Basic { } catch (CancellationException x) { } - // check that completion handler executed. - latch.await(); + // check that the cancel doesn't impact writing to the channel + if (!mayInterruptIfRunning) { + buf = ByteBuffer.wrap("a".getBytes()); + ch.write(buf).get(); + } ch.close(); peer.close(); @@ -408,8 +397,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); latch.await(); @@ -460,8 +447,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // trickle the writing @@ -507,26 +492,24 @@ public class Basic { } // scattering read that completes ascynhronously - final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch l1 = new CountDownLatch(1); ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, (Void)null, new CompletionHandler() { public void completed(Long result, Void att) { long n = result; if (n <= 0) throw new RuntimeException("No bytes read"); - latch.countDown(); + l1.countDown(); } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // write some bytes sc.write(genBuffer()); // read should now complete - latch.await(); + l1.await(); // write more bytes sc.write(genBuffer()); @@ -535,10 +518,20 @@ public class Basic { for (int i=0; i() { + public void completed(Long result, Void att) { + long n = result; + if (n <= 0) + throw new RuntimeException("No bytes read"); + l2.countDown(); + } + public void failed(Throwable exc, Void att) { + } + }); + l2.await(); ch.close(); sc.close(); @@ -574,8 +567,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // read to EOF or buffer full @@ -613,19 +604,29 @@ public class Basic { ch.connect(server.address()).get(); SocketChannel sc = server.accept(); + // number of bytes written + final AtomicLong bytesWritten = new AtomicLong(0); + // write buffers (should complete immediately) ByteBuffer[] srcs = genBuffers(1); - long n = ch - .write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, (Void)null, null).get(); - if (n <= 0) - throw new RuntimeException("No bytes written"); + final CountDownLatch l1 = new CountDownLatch(1); + ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, (Void)null, + new CompletionHandler() { + public void completed(Long result, Void att) { + long n = result; + if (n <= 0) + throw new RuntimeException("No bytes read"); + bytesWritten.addAndGet(n); + l1.countDown(); + } + public void failed(Throwable exc, Void att) { + } + }); + l1.await(); // set to true to signal that no more buffers should be written final AtomicBoolean continueWriting = new AtomicBoolean(true); - // number of bytes written - final AtomicLong bytesWritten = new AtomicLong(n); - // write until socket buffer is full so as to create the conditions // for when a write does not complete immediately srcs = genBuffers(1); @@ -644,8 +645,6 @@ public class Basic { } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // give time for socket buffer to fill up. @@ -658,7 +657,7 @@ public class Basic { ByteBuffer buf = ByteBuffer.allocateDirect(4096); long total = 0L; do { - n = sc.read(buf); + int n = sc.read(buf); if (n <= 0) throw new RuntimeException("No bytes read"); buf.rewind(); @@ -714,15 +713,27 @@ public class Basic { System.out.println("-- timeout when reading --"); - // this read should timeout ByteBuffer dst = ByteBuffer.allocate(512); - try { - ch.read(dst, 3, TimeUnit.SECONDS, (Void)null, null).get(); - throw new RuntimeException("Read did not timeout"); - } catch (ExecutionException x) { - if (!(x.getCause() instanceof InterruptedByTimeoutException)) - throw new RuntimeException("InterruptedByTimeoutException expected"); + + final AtomicReference readException = new AtomicReference(); + + // this read should timeout + ch.read(dst, 3, TimeUnit.SECONDS, (Void)null, + new CompletionHandler() + { + public void completed(Integer result, Void att) { + throw new RuntimeException("Should not complete"); + } + public void failed(Throwable exc, Void att) { + readException.set(exc); + } + }); + // wait for exception + while (readException.get() == null) { + Thread.sleep(100); } + if (!(readException.get() instanceof InterruptedByTimeoutException)) + throw new RuntimeException("InterruptedByTimeoutException expected"); // after a timeout then further reading should throw unspecified runtime exception boolean exceptionThrown = false; @@ -752,8 +763,6 @@ public class Basic { public void failed(Throwable exc, AsynchronousSocketChannel ch) { writeException.set(exc); } - public void cancelled(AsynchronousSocketChannel ch) { - } }); // wait for exception diff --git a/test/java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java b/test/java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java new file mode 100644 index 0000000000000000000000000000000000000000..1f4efb845df17ae70138b2418fb8b652e8d2fe7c --- /dev/null +++ b/test/java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java @@ -0,0 +1,136 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6842687 + * @summary Unit test for AsynchronousSocketChannel/AsynchronousServerSocketChannel + */ +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Initiates I/O operation on a thread that terminates before the I/O completes. + */ + +public class DieBeforeComplete { + + public static void main(String[] args) throws Exception { + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0)); + + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress) (listener.getLocalAddress())).getPort(); + final SocketAddress sa = new InetSocketAddress(lh, port); + + // -- accept -- + + // initiate accept in a thread that dies before connection is established + Future r1 = + initiateAndDie(new Task() { + public Future run() { + return listener.accept(); + }}); + + // establish and accept connection + SocketChannel peer = SocketChannel.open(sa); + final AsynchronousSocketChannel channel = r1.get(); + + // --- read -- + + // initiate read in a thread that dies befores bytes are available + final ByteBuffer dst = ByteBuffer.allocate(100); + Future r2 = initiateAndDie(new Task() { + public Future run() { + return channel.read(dst); + }}); + + // send bytes + peer.write(ByteBuffer.wrap("hello".getBytes())); + int nread = r2.get(); + if (nread <= 0) + throw new RuntimeException("Should have read at least one byte"); + + // -- write -- + + // initiate writes in threads that dies + boolean completedImmediately; + Future r3; + do { + final ByteBuffer src = ByteBuffer.wrap(new byte[10000]); + r3 = initiateAndDie(new Task() { + public Future run() { + return channel.write(src); + }}); + try { + int nsent = r3.get(5, TimeUnit.SECONDS); + if (nsent <= 0) + throw new RuntimeException("Should have wrote at least one byte"); + completedImmediately = true; + } catch (TimeoutException x) { + completedImmediately = false; + } + } while (completedImmediately); + + // drain connection + peer.configureBlocking(false); + ByteBuffer src = ByteBuffer.allocateDirect(10000); + do { + src.clear(); + nread = peer.read(src); + if (nread == 0) { + Thread.sleep(100); + nread = peer.read(src); + } + } while (nread > 0); + + // write should complete now + int nsent = r3.get(); + if (nsent <= 0) + throw new RuntimeException("Should have wrote at least one byte"); + } + + static interface Task { + Future run(); + } + + static Future initiateAndDie(final Task task) { + final AtomicReference> result = new AtomicReference>(); + Runnable r = new Runnable() { + public void run() { + result.set(task.run()); + } + }; + Thread t = new Thread(r); + t.start(); + while (t.isAlive()) { + try { + t.join(); + } catch (InterruptedException x) { + } + } + return result.get(); + } +} diff --git a/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java b/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java index a3c0db687e684b2c8df7d57eaecbf66321fcb0d2..bb77552fcb058ac5c06c587f87b09acc7918df3b 100644 --- a/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java +++ b/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 6834246 + * @bug 6834246 6842687 * @summary Stress test connections through the loopback interface */ @@ -114,8 +114,6 @@ public class StressLoopback { exc.printStackTrace(); closeUnchecked(channel); } - public void cancelled(Void att) { - } }); } @@ -156,8 +154,6 @@ public class StressLoopback { exc.printStackTrace(); closeUnchecked(channel); } - public void cancelled(Void att) { - } }); } diff --git a/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java b/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java index c7ed16a920475deb94eff42808139cdbb2f675f5..055ff55e8f17a0de3edbe87e947cead9b7300f18 100644 --- a/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java +++ b/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 6543863 + * @bug 6543863 6842687 * @summary Try to cause a deadlock between (Asynchronous)FileChannel.close * and FileLock.release */ @@ -56,7 +56,7 @@ public class ReleaseOnCloseDeadlock { AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, READ, WRITE); for (int i=0; i permissionsChecked = new ArrayList(); + private Set propertiesChecked = new HashSet(); + private List readsChecked = new ArrayList(); + private List writesChecked = new ArrayList(); + private List deletesChecked = new ArrayList(); + private List execsChecked = new ArrayList(); + + List permissionsChecked() { return permissionsChecked; } + Set propertiesChecked() { return propertiesChecked; } + List readsChecked() { return readsChecked; } + List writesChecked() { return writesChecked; } + List deletesChecked() { return deletesChecked; } + List execsChecked() { return execsChecked; } + } + + static ThreadLocal myChecks = + new ThreadLocal() { + @Override protected Checks initialValue() { + return null; + } + }; + + static void prepare() { + myChecks.set(new Checks()); + } + + static void assertCheckPermission(Class type, + String name) + { + for (Permission perm: myChecks.get().permissionsChecked()) { + if (type.isInstance(perm) && perm.getName().equals(name)) + return; + } + throw new RuntimeException(type.getName() + "\"" + name + "\") not checked"); + } + + static void assertCheckPropertyAccess(String key) { + if (!myChecks.get().propertiesChecked().contains(key)) + throw new RuntimeException("Property " + key + " not checked"); + } + + static void assertChecked(Path file, List list) { + String s = file.toString(); + for (String f: list) { + if (f.endsWith(s)) + return; + } + throw new RuntimeException("Access not checked"); + } + + static void assertCheckRead(Path file) { + assertChecked(file, myChecks.get().readsChecked()); + } + + static void assertCheckWrite(Path file) { + assertChecked(file, myChecks.get().writesChecked()); + } + + static void assertCheckDelete(Path file) { + assertChecked(file, myChecks.get().deletesChecked()); + } + + static void assertCheckExec(Path file) { + assertChecked(file, myChecks.get().execsChecked()); + } + + static class LoggingSecurityManager extends SecurityManager { + static void install() { + System.setSecurityManager(new LoggingSecurityManager()); + } + + @Override + public void checkPermission(Permission perm) { + Checks checks = myChecks.get(); + if (checks != null) + checks.permissionsChecked().add(perm); + } + + @Override + public void checkPropertyAccess(String key) { + Checks checks = myChecks.get(); + if (checks != null) + checks.propertiesChecked().add(key); + } + + @Override + public void checkRead(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.readsChecked().add(file); + } + + @Override + public void checkWrite(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.writesChecked().add(file); + } + + @Override + public void checkDelete(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.deletesChecked().add(file); + } + + @Override + public void checkExec(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.execsChecked().add(file); + } + } + + static void testBasicFileAttributeView(BasicFileAttributeView view, Path file) + throws IOException + { + prepare(); + view.readAttributes(); + assertCheckRead(file); + + prepare(); + FileTime now = FileTime.fromMillis(System.currentTimeMillis()); + view.setTimes(null, now, now); + assertCheckWrite(file); + } + + static void testPosixFileAttributeView(PosixFileAttributeView view, Path file) + throws IOException + { + prepare(); + PosixFileAttributes attrs = view.readAttributes(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setPermissions(attrs.permissions()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(attrs.owner()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(attrs.owner()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + } + + public static void main(String[] args) throws IOException { + Path dir = Paths.get(System.getProperty("test.src", ".")); + Path file = dir.resolve("file1234").createFile(); + try { + LoggingSecurityManager.install(); + + // -- checkAccess -- + + prepare(); + file.checkAccess(); + assertCheckRead(file); + + prepare(); + file.checkAccess(AccessMode.READ); + assertCheckRead(file); + + prepare(); + file.checkAccess(AccessMode.WRITE); + assertCheckWrite(file); + + prepare(); + try { + file.checkAccess(AccessMode.EXECUTE); + } catch (AccessDeniedException x) { } + assertCheckExec(file); + + prepare(); + try { + file.checkAccess(AccessMode.READ, AccessMode.WRITE, AccessMode.EXECUTE); + } catch (AccessDeniedException x) { } + assertCheckRead(file); + assertCheckWrite(file); + assertCheckExec(file); + + // -- copyTo -- + + Path target = dir.resolve("target1234"); + prepare(); + file.copyTo(target); + try { + assertCheckRead(file); + assertCheckWrite(target); + } finally { + target.delete(); + } + + if (TestUtil.supportsLinks(dir)) { + Path link = dir.resolve("link1234").createSymbolicLink(file); + try { + prepare(); + link.copyTo(target, LinkOption.NOFOLLOW_LINKS); + try { + assertCheckRead(link); + assertCheckWrite(target); + assertCheckPermission(LinkPermission.class, "symbolic"); + } finally { + target.delete(); + } + } finally { + link.delete(); + } + } + + // -- createDirectory -- + + Path subdir = dir.resolve("subdir1234"); + prepare(); + subdir.createDirectory(); + try { + assertCheckWrite(subdir); + } finally { + subdir.delete(); + } + + // -- createFile -- + + Path fileToCreate = dir.resolve("file7890"); + prepare(); + try { + fileToCreate.createFile(); + assertCheckWrite(fileToCreate); + } finally { + fileToCreate.delete(); + } + + // -- createSymbolicLink -- + + if (TestUtil.supportsLinks(dir)) { + prepare(); + Path link = dir.resolve("link1234").createSymbolicLink(file); + try { + assertCheckWrite(link); + assertCheckPermission(LinkPermission.class, "symbolic"); + } finally { + link.delete(); + } + } + + // -- delete/deleteIfExists -- + + Path fileToDelete = dir.resolve("file7890"); + + fileToDelete.createFile(); + prepare(); + fileToDelete.delete(); + assertCheckDelete(fileToDelete); + + fileToDelete.createFile(); + prepare(); + fileToDelete.deleteIfExists(); + assertCheckDelete(fileToDelete); + + // -- exists/notExists -- + + prepare(); + file.exists(); + assertCheckRead(file); + + prepare(); + file.notExists(); + assertCheckRead(file); + + // -- getFileStore -- + + prepare(); + file.getFileStore(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "getFileStoreAttributes"); + + // -- isSameFile -- + + prepare(); + file.isSameFile(dir); + assertCheckRead(file); + assertCheckRead(dir); + + // -- moveTo -- + + Path target2 = dir.resolve("target1234"); + prepare(); + file.moveTo(target2); + try { + assertCheckWrite(file); + assertCheckWrite(target2); + } finally { + // restore file + target2.moveTo(file); + } + + // -- newByteChannel -- + + SeekableByteChannel sbc; + + prepare(); + sbc = file.newByteChannel(); + try { + assertCheckRead(file); + } finally { + sbc.close(); + } + prepare(); + sbc = file.newByteChannel(StandardOpenOption.WRITE); + try { + assertCheckWrite(file); + } finally { + sbc.close(); + } + prepare(); + sbc = file.newByteChannel(StandardOpenOption.READ, StandardOpenOption.WRITE); + try { + assertCheckRead(file); + assertCheckWrite(file); + } finally { + sbc.close(); + } + + prepare(); + sbc = file.newByteChannel(StandardOpenOption.DELETE_ON_CLOSE); + try { + assertCheckRead(file); + assertCheckDelete(file); + } finally { + sbc.close(); + } + file.createFile(); // restore file + + + // -- newInputStream/newOutptuStream -- + + prepare(); + InputStream in = file.newInputStream(); + try { + assertCheckRead(file); + } finally { + in.close(); + } + prepare(); + OutputStream out = file.newOutputStream(); + try { + assertCheckWrite(file); + } finally { + out.close(); + } + + // -- newDirectoryStream -- + + prepare(); + DirectoryStream stream = dir.newDirectoryStream(); + try { + assertCheckRead(dir); + + if (stream instanceof SecureDirectoryStream) { + Path entry; + SecureDirectoryStream sds = + (SecureDirectoryStream)stream; + + // newByteChannel + entry = file.getName(); + prepare(); + sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.READ)); + try { + assertCheckRead(file); + } finally { + sbc.close(); + } + prepare(); + sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.WRITE)); + try { + assertCheckWrite(file); + } finally { + sbc.close(); + } + + // deleteFile + entry = file.getName(); + prepare(); + sds.deleteFile(entry); + assertCheckDelete(file); + dir.resolve(entry).createFile(); // restore file + + // deleteDirectory + entry = Paths.get("subdir1234"); + dir.resolve(entry).createDirectory(); + prepare(); + sds.deleteDirectory(entry); + assertCheckDelete(dir.resolve(entry)); + + // move + entry = Paths.get("tempname1234"); + prepare(); + sds.move(file.getName(), sds, entry); + assertCheckWrite(file); + assertCheckWrite(dir.resolve(entry)); + sds.move(entry, sds, file.getName()); // restore file + + // newDirectoryStream + entry = Paths.get("subdir1234"); + dir.resolve(entry).createDirectory(); + try { + prepare(); + sds.newDirectoryStream(entry).close(); + assertCheckRead(dir.resolve(entry)); + } finally { + dir.resolve(entry).delete(); + } + + // getFileAttributeView to access attributes of directory + testBasicFileAttributeView(sds + .getFileAttributeView(BasicFileAttributeView.class), dir); + testPosixFileAttributeView(sds + .getFileAttributeView(PosixFileAttributeView.class), dir); + + // getFileAttributeView to access attributes of entry + entry = file.getName(); + testBasicFileAttributeView(sds + .getFileAttributeView(entry, BasicFileAttributeView.class), file); + testPosixFileAttributeView(sds + .getFileAttributeView(entry, PosixFileAttributeView.class), file); + + } else { + System.out.println("SecureDirectoryStream not tested"); + } + + } finally { + stream.close(); + } + + // -- toAbsolutePath -- + + prepare(); + file.getName().toAbsolutePath(); + assertCheckPropertyAccess("user.dir"); + + // -- toRealPath -- + + prepare(); + file.toRealPath(true); + assertCheckRead(file); + + prepare(); + file.toRealPath(false); + assertCheckRead(file); + + prepare(); + Paths.get(".").toRealPath(true); + assertCheckPropertyAccess("user.dir"); + + prepare(); + Paths.get(".").toRealPath(false); + assertCheckPropertyAccess("user.dir"); + + // -- register -- + + WatchService watcher = FileSystems.getDefault().newWatchService(); + try { + prepare(); + dir.register(watcher, StandardWatchEventKind.ENTRY_DELETE); + assertCheckRead(dir); + } finally { + watcher.close(); + } + + // -- getAttribute/setAttribute/readAttributes -- + + prepare(); + file.getAttribute("size"); + assertCheckRead(file); + + prepare(); + file.setAttribute("lastModifiedTime", + FileTime.fromMillis(System.currentTimeMillis())); + assertCheckWrite(file); + + prepare(); + file.readAttributes("*"); + assertCheckRead(file); + + // -- BasicFileAttributeView -- + testBasicFileAttributeView(file + .getFileAttributeView(BasicFileAttributeView.class), file); + + // -- PosixFileAttributeView -- + + { + PosixFileAttributeView view = + file.getFileAttributeView(PosixFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(PosixFileAttributeView.class)) + { + testPosixFileAttributeView(view, file); + } else { + System.out.println("PosixFileAttributeView not tested"); + } + } + + // -- DosFileAttributeView -- + + { + DosFileAttributeView view = + file.getFileAttributeView(DosFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(DosFileAttributeView.class)) + { + prepare(); + view.readAttributes(); + assertCheckRead(file); + + prepare(); + view.setArchive(false); + assertCheckWrite(file); + + prepare(); + view.setHidden(false); + assertCheckWrite(file); + + prepare(); + view.setReadOnly(false); + assertCheckWrite(file); + + prepare(); + view.setSystem(false); + assertCheckWrite(file); + } else { + System.out.println("DosFileAttributeView not tested"); + } + } + + // -- FileOwnerAttributeView -- + + { + FileOwnerAttributeView view = + file.getFileAttributeView(FileOwnerAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(FileOwnerAttributeView.class)) + { + prepare(); + UserPrincipal owner = view.getOwner(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(owner); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + } else { + System.out.println("FileOwnerAttributeView not tested"); + } + } + + // -- UserDefinedFileAttributeView -- + + { + UserDefinedFileAttributeView view = + file.getFileAttributeView(UserDefinedFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(UserDefinedFileAttributeView.class)) + { + prepare(); + view.write("test", ByteBuffer.wrap(new byte[100])); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.read("test", ByteBuffer.allocate(100)); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.size("test"); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.list(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.delete("test"); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + } else { + System.out.println("UserDefinedFileAttributeView not tested"); + } + } + + // -- AclFileAttributeView -- + { + AclFileAttributeView view = + file.getFileAttributeView(AclFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(AclFileAttributeView.class)) + { + prepare(); + List acl = view.getAcl(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + prepare(); + view.setAcl(acl); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + } else { + System.out.println("AclFileAttributeView not tested"); + } + } + + // -- UserPrincipalLookupService + + UserPrincipalLookupService lookupService = + FileSystems.getDefault().getUserPrincipalLookupService(); + UserPrincipal owner = Attributes.getOwner(file); + + prepare(); + lookupService.lookupPrincipalByName(owner.getName()); + assertCheckPermission(RuntimePermission.class, + "lookupUserInformation"); + + try { + UserPrincipal group = Attributes.readPosixFileAttributes(file).group(); + prepare(); + lookupService.lookupPrincipalByGroupName(group.getName()); + assertCheckPermission(RuntimePermission.class, + "lookupUserInformation"); + } catch (UnsupportedOperationException ignore) { + System.out.println("lookupPrincipalByGroupName not tested"); + } + + + } finally { + file.deleteIfExists(); + } + } +} diff --git a/test/java/nio/file/Path/Misc.java b/test/java/nio/file/Path/Misc.java index 07418844fd8e2eb2d38864c8fdc365b85aa6c104..9e5452c89883ebc2e0fbdbd725bdb28432163897 100644 --- a/test/java/nio/file/Path/Misc.java +++ b/test/java/nio/file/Path/Misc.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6866804 + * @bug 4313887 6838333 6867101 * @summary Unit test for java.nio.file.Path for miscellenous methods not * covered by other tests * @library .. diff --git a/test/java/nio/file/PathMatcher/Basic.java b/test/java/nio/file/PathMatcher/Basic.java index 16efcf099d08e41f7257cf79151ae5c154a72167..3050eb30ae7b6fdaa33c6074f93261f7fb4cefe7 100644 --- a/test/java/nio/file/PathMatcher/Basic.java +++ b/test/java/nio/file/PathMatcher/Basic.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 + * @bug 4313887 6866397 * @summary Unit test for java.nio.file.PathMatcher */ @@ -68,6 +68,20 @@ public class Basic { } } + static void assertRegExMatch(String path, String pattern) { + System.out.format("Test regex pattern: %s", pattern); + Path file = Paths.get(path); + boolean matched = file.getFileSystem() + .getPathMatcher("regex:" + pattern).matches(file); + if (matched) { + System.out.println(" OKAY"); + } else { + System.out.println(" ==> UNEXPECTED RESULT!"); + failures++; + } + } + + public static void main(String[] args) { // basic assertMatch("foo.html", "foo.html"); @@ -140,21 +154,13 @@ public class Basic { assertMatch("one*two", "one\\*two"); } - - // regex syntax - { - String pattern = ".*\\.html"; - System.out.format("Test regex pattern: %s", pattern); - Path file = Paths.get("foo.html"); - boolean matched = file.getFileSystem() - .getPathMatcher("regex:" + pattern).matches(file); - if (matched) { - System.out.println(" OKAY"); - } else { - System.out.println(" ==> UNEXPECTED RESULT!"); - failures++; - } + assertRegExMatch("foo.html", ".*\\.html"); + + if (System.getProperty("os.name").startsWith("Windows")) { + assertRegExMatch("foo012", "foo\\d+"); + assertRegExMatch("fo o", "fo\\so"); + assertRegExMatch("foo", "\\w+"); } // unknown syntax diff --git a/test/java/util/prefs/CommentsInXml.java b/test/java/util/prefs/CommentsInXml.java new file mode 100644 index 0000000000000000000000000000000000000000..b65cfa29e7db7379c3cc4add683af51be79bbe3a --- /dev/null +++ b/test/java/util/prefs/CommentsInXml.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 4619564 + * @summary XMl Comments in Preferences File lead to ClassCastException + * @author kladko + */ + +import java.io.*; +import java.util.prefs.*; + +public class CommentsInXml { + + public static void main(String[] argv) throws Exception { + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + bos.write(new String( + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + ).getBytes()); + + Preferences ur = Preferences.userRoot(); + ur.importPreferences(new ByteArrayInputStream(bos.toByteArray())); + ur.node("hlrAgent").removeNode(); // clean + } +} diff --git a/test/java/util/prefs/ConflictInFlush.java b/test/java/util/prefs/ConflictInFlush.java new file mode 100644 index 0000000000000000000000000000000000000000..598b909d34598701251a6785550234c2f22eab39 --- /dev/null +++ b/test/java/util/prefs/ConflictInFlush.java @@ -0,0 +1,49 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 4703132 + * @summary flush() throws an IllegalStateException on a removed node + * @author Sucheta Dambalkar + */ + +import java.util.prefs.*; + +public final class ConflictInFlush{ + + public static void main(String args[]) { + Preferences root = Preferences.userRoot(); + try { + Preferences node = root.node("1/2/3"); + node.flush(); + System.out.println("Node "+node+" has been created"); + System.out.println("Removing node "+node); + node.removeNode(); + node.flush(); + }catch (BackingStoreException bse){ + bse.printStackTrace(); + } + + } +} diff --git a/test/java/util/prefs/ExportNode.java b/test/java/util/prefs/ExportNode.java new file mode 100644 index 0000000000000000000000000000000000000000..5ab802efb590e63207cd440ef3d4f4851f20fcb4 --- /dev/null +++ b/test/java/util/prefs/ExportNode.java @@ -0,0 +1,53 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * @test + * @bug 4387136 4947349 + * @summary Due to a bug in XMLSupport.putPreferencesInXml(...), + * node's keys would not get exported. + * @author Konstantin Kladko + */ +import java.util.prefs.*; +import java.io.*; + +public class ExportNode { + public static void main(String[] args) throws + BackingStoreException, IOException { + Preferences N1 = Preferences.userRoot().node("ExportNodeTest1"); + N1.put("ExportNodeTestName1","ExportNodeTestValue1"); + Preferences N2 = N1.node("ExportNodeTest2"); + N2.put("ExportNodeTestName2","ExportNodeTestValue2"); + ByteArrayOutputStream exportStream = new ByteArrayOutputStream(); + N2.exportNode(exportStream); + + // Removal of preference node should always succeed on Solaris/Linux + // by successfully acquiring the appropriate file lock (4947349) + N1.removeNode(); + + if (((exportStream.toString()).lastIndexOf("ExportNodeTestName2")== -1) || + ((exportStream.toString()).lastIndexOf("ExportNodeTestName1")!= -1)) { + } + } +} diff --git a/test/java/util/prefs/ExportSubtree.java b/test/java/util/prefs/ExportSubtree.java new file mode 100644 index 0000000000000000000000000000000000000000..c3d4cd7e936ac650ecdeddf77b3636a827e7ce02 --- /dev/null +++ b/test/java/util/prefs/ExportSubtree.java @@ -0,0 +1,95 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + @bug 6203576 4700020 + @summary checks if the output of exportSubtree() is identical to + the output from previous release. + */ + +import java.io.*; +import java.util.prefs.*; + +public class ExportSubtree { + public static void main(String[] args) throws Exception { + try + { + //File f = new File(System.getProperty("test.src", "."), "TestPrefs.xml"); + ByteArrayInputStream bais = new ByteArrayInputStream(importPrefs.getBytes("utf-8")); + Preferences.importPreferences(bais); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Preferences.userRoot().node("testExportSubtree").exportSubtree(baos); + Preferences.userRoot().node("testExportSubtree").removeNode(); + if (!expectedResult.equals(baos.toString())) { + //System.out.print(baos.toString()); + //System.out.print(expectedResult); + throw new IOException("exportSubtree does not output expected result"); + } + } + catch( Exception e ) { + e.printStackTrace(); + } + } + + static String ls = System.getProperty("line.separator"); + static String importPrefs = + "" + + "" + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + + static String expectedResult = + "" + + ls + "" + + ls + "" + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + "" + ls; +} diff --git a/test/java/util/prefs/PrefsSpi.java b/test/java/util/prefs/PrefsSpi.java new file mode 100644 index 0000000000000000000000000000000000000000..2009ae2d51270159f3734bce0650e323f78a1fa2 --- /dev/null +++ b/test/java/util/prefs/PrefsSpi.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +import java.util.prefs.Preferences; + +/* + * main class used by regtest PrefsSpi.sh + */ +public class PrefsSpi { + + public static void main (String[] args) throws Exception { + if (args.length != 1) + throw new Exception("Usage: java PrefsSpi REGEXP"); + + String className = Preferences.userRoot().getClass().getName(); + System.out.printf("className=%s%n", className); + + if (! className.matches(args[0])) + throw new Exception("Preferences class name \"" + className + + "\" does not match regular expression \"" + + args[0] + "\"."); + } +} diff --git a/test/java/util/prefs/PrefsSpi.sh b/test/java/util/prefs/PrefsSpi.sh new file mode 100644 index 0000000000000000000000000000000000000000..3d8e28b7afd47bbec529100677338155766ea89c --- /dev/null +++ b/test/java/util/prefs/PrefsSpi.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4991526 6514993 +# @summary Unit test for Preferences jar providers +# +# @build PrefsSpi +# @run shell PrefsSpi.sh +# @author Martin Buchholz + +# Command-line usage: sh PrefsSpi.sh /path/to/build + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + + java="$TESTJAVA/bin/java" +javac="$TESTJAVA/bin/javac" + jar="$TESTJAVA/bin/jar" + +Die() { printf "%s\n" "$*"; exit 1; } + +Sys() { + printf "%s\n" "$*"; "$@"; rc="$?"; + test "$rc" -eq 0 || Die "Command \"$*\" failed with exitValue $rc"; +} + +cat > StubPreferences.java <<'EOF' +import java.util.prefs.*; + +public class StubPreferences extends AbstractPreferences { + public StubPreferences() { super(null, ""); } + public String getSpi(String x) { return null; } + public void putSpi(String x, String y) { } + public void removeSpi(String x) { } + public AbstractPreferences childSpi(String x) { return null; } + public void removeNodeSpi() { } + public String[] keysSpi() { return null; } + public String[] childrenNamesSpi() { return null; } + public void syncSpi() { } + public void flushSpi() { } +} +EOF + +cat > StubPreferencesFactory.java <<'EOF' +import java.util.prefs.*; + +public class StubPreferencesFactory implements PreferencesFactory { + public Preferences userRoot() { return new StubPreferences(); } + public Preferences systemRoot() { return new StubPreferences(); } +} +EOF + +Sys rm -rf jarDir extDir +Sys mkdir -p jarDir/META-INF/services extDir +echo "StubPreferencesFactory" \ + > "jarDir/META-INF/services/java.util.prefs.PreferencesFactory" +Sys "$javac" -d jarDir StubPreferencesFactory.java StubPreferences.java + +(cd jarDir && "$jar" "cf" "../extDir/PrefsSpi.jar" ".") + +case "`uname`" in Windows*|CYGWIN* ) CPS=';';; *) CPS=':';; esac + +Sys "$java" "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \ + -Djava.util.prefs.PreferencesFactory=StubPreferencesFactory \ + PrefsSpi "StubPreferences" +Sys "$java" "-cp" "$TESTCLASSES" \ + PrefsSpi "java.util.prefs.*" +Sys "$java" "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \ + PrefsSpi "StubPreferences" +Sys "$java" "-cp" "$TESTCLASSES" "-Djava.ext.dirs=extDir" \ + PrefsSpi "StubPreferences" + +rm -rf jarDir extDir diff --git a/test/java/util/prefs/RemoveReadOnlyNode.java b/test/java/util/prefs/RemoveReadOnlyNode.java new file mode 100644 index 0000000000000000000000000000000000000000..82409dfc637cd1c9aef3573196b142079239d61d --- /dev/null +++ b/test/java/util/prefs/RemoveReadOnlyNode.java @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + @bug 6178148 + @summary check if wrong exception gets thrown if one of the child + nodes is readonly on underlying filesystem when node is + being removed. + */ + +import java.io.*; +import java.util.prefs.*; + +public class RemoveReadOnlyNode { + public static void main(String[] args) throws Exception { + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) + return; + Preferences root = Preferences.userRoot(); + Preferences node1 = root.node("node1"); + Preferences node1A = node1.node("node1A"); + Preferences node1B = node1.node("node1B"); + node1B.put("mykey", "myvalue"); + node1.flush(); + String node1BDirName = System.getProperty("user.home") + + "/.java/.userPrefs" + + "/node1/node1B"; + File node1BDir = new File(node1BDirName); + node1BDir.setReadOnly(); + try { + node1.removeNode(); + } + catch (BackingStoreException ex) { + //expected exception + } finally { + Runtime.getRuntime().exec("chmod 755 " + node1BDirName).waitFor(); + try { + node1.removeNode(); + } catch (Exception e) {} + } + } +} diff --git a/test/java/util/prefs/RemoveUnregedListener.java b/test/java/util/prefs/RemoveUnregedListener.java new file mode 100644 index 0000000000000000000000000000000000000000..d48e42b4cb71027f5ad4ffa806fe34e1c60fe1c3 --- /dev/null +++ b/test/java/util/prefs/RemoveUnregedListener.java @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + * @bug 4705094 + * @summary Checks if correct exception gets thrown when removing an + * unregistered NodeChangeListener . + */ + +import java.util.prefs.*; +import java.util.*; + +public class RemoveUnregedListener { + public static void main(String[] args) throws Exception { + Preferences userRoot = null; + Preferences N1 = null; + NodeChangeListenerTestAdd ncl = new NodeChangeListenerTestAdd(); + NodeChangeListenerTestAdd ncl2 = new NodeChangeListenerTestAdd(); + NodeChangeListenerTestAdd ncl3 = new NodeChangeListenerTestAdd(); + try { + userRoot = Preferences.userRoot(); + N1 = userRoot.node("N1"); + userRoot.flush(); + + //add ncl nc2 + N1.addNodeChangeListener(ncl); + N1.addNodeChangeListener(ncl2); + N1.removeNodeChangeListener(ncl3); + throw new RuntimeException(); + } catch (IllegalArgumentException iae) { + System.out.println("Test Passed!"); + } catch (Exception e) { + System.out.println("Test Failed"); + throw e; + } + } + +} +class NodeChangeListenerTestAdd implements NodeChangeListener { + public void childAdded(NodeChangeEvent evt) {} + public void childRemoved(NodeChangeEvent evt) {} +} diff --git a/test/java/util/prefs/SerializeExceptions.java b/test/java/util/prefs/SerializeExceptions.java new file mode 100644 index 0000000000000000000000000000000000000000..04e4ae3e7dd4f8d6853d0962972d4ac42e416014 --- /dev/null +++ b/test/java/util/prefs/SerializeExceptions.java @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * @test + * @bug 4811356 + * @summary Prefs exceptions were unintentionally not serializable + * @author Josh Bloch + */ + +import java.util.prefs.*; +import java.io.*; + +public class SerializeExceptions { + public static void main(String args[]) throws Exception { + test(new BackingStoreException("Hi")); + test(new InvalidPreferencesFormatException("Mom!")); + } + + static void test(Object o) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos); + out.writeObject(o); + out.flush(); + out.close(); + } +} diff --git a/test/sun/nio/cs/FindCanEncodeBugs.java b/test/sun/nio/cs/FindCanEncodeBugs.java index 7331934d5da0c9651033fab0e6d8149b1c9e811e..2fc6218995d18e09ab2652b6c9a2afa55c72b6b0 100644 --- a/test/sun/nio/cs/FindCanEncodeBugs.java +++ b/test/sun/nio/cs/FindCanEncodeBugs.java @@ -22,7 +22,7 @@ */ /* @test - @bug 5066863 5066867 5066874 5066879 5066884 5066887 5065777 + @bug 5066863 5066867 5066874 5066879 5066884 5066887 5065777 6730652 @summary canEncode() false iff encode() throws CharacterCodingException @run main/timeout=1200 FindCanEncodeBugs @author Martin Buchholz @@ -52,9 +52,7 @@ public class FindCanEncodeBugs { String csn = e.getKey(); Charset cs = e.getValue(); - if (! cs.canEncode() || - csn.matches("x-COMPOUND_TEXT") || - csn.matches("x-ISO-2022-CN-CNS")) // ISO2022_CN_CNS supports less + if (! cs.canEncode() || csn.matches("x-COMPOUND_TEXT")) continue; //System.out.println(csn); diff --git a/test/sun/security/ec/TestEC.java b/test/sun/security/ec/TestEC.java index 0f87692a01a31a4c9fe308172ac55abcb4b92466..12694a03c649fbd2e3ac1a1b2bec8c94cf6abc63 100644 --- a/test/sun/security/ec/TestEC.java +++ b/test/sun/security/ec/TestEC.java @@ -53,7 +53,7 @@ public class TestEC { long start = System.currentTimeMillis(); new TestECDH().main(p); new TestECDSA().main(p); - //new TestCurves().main(p); + new TestCurves().main(p); new TestKeyFactory().main(p); new TestECGenSpec().main(p); new ReadPKCS12().main(p); diff --git a/test/sun/security/krb5/ktab/HighestKvno.java b/test/sun/security/krb5/ktab/HighestKvno.java new file mode 100644 index 0000000000000000000000000000000000000000..3f315f81d9228cb98c78d664f3507056752009b4 --- /dev/null +++ b/test/sun/security/krb5/ktab/HighestKvno.java @@ -0,0 +1,235 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test + * @bug 6867665 + * @bug 6875033 + * @summary Problem with keytabs with multiple kvno's (key versions) + */ + +import sun.security.krb5.internal.ktab.*; +import sun.security.krb5.*; +import java.io.File; +import java.io.FileOutputStream; + +public class HighestKvno { + + public static void main(String[] args) throws Exception { + // kt is a keytab including these entries: + // + // me@MAD.LOCAL: Type: 3, KVNO: 4 + // me@MAD.LOCAL: Type: 23, KVNO: 4 + // me@MAD.LOCAL: Type: 16, KVNO: 4 + // me@MAD.LOCAL: Type: 1, KVNO: 5 + // me@MAD.LOCAL: Type: 17, KVNO: 5 + // me@MAD.LOCAL: Type: 18, KVNO: 5 + // me@MAD.LOCAL: Type: 1, KVNO: 3 + // me@MAD.LOCAL: Type: 17, KVNO: 3 + // me@MAD.LOCAL: Type: 18, KVNO: 3 + // he@MAD.LOCAL: Type: 1, KVNO: 1 + // he@MAD.LOCAL: Type: 17, KVNO: 1 + // he@MAD.LOCAL: Type: 18, KVNO: 1 + // + // This file is created with these steps: + // 1. Modify JRE's Ktab.java so that adding new entries + // does not remove the old one. + // 2. Run the modified Ktab to create 4 sets of keys + // 3. Manually hex edit the KVNO as above + + byte[] kt = { + (byte)0x05, (byte)0x02, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x45, (byte)0xCD, (byte)0x04, + (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x08, + (byte)0xE6, (byte)0xB0, (byte)0x07, (byte)0xA8, + (byte)0x5B, (byte)0xF8, (byte)0x73, (byte)0xAD, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x2E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x45, + (byte)0xCD, (byte)0x04, (byte)0x00, (byte)0x17, + (byte)0x00, (byte)0x10, (byte)0x50, (byte)0x92, + (byte)0x01, (byte)0x6B, (byte)0xCF, (byte)0x5A, + (byte)0x2A, (byte)0x7A, (byte)0x4F, (byte)0xE8, + (byte)0x39, (byte)0xD9, (byte)0x90, (byte)0xB5, + (byte)0x9C, (byte)0xEB, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x36, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x45, (byte)0xCD, (byte)0x04, + (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x18, + (byte)0xDF, (byte)0xDF, (byte)0x62, (byte)0x86, + (byte)0x37, (byte)0xCE, (byte)0x29, (byte)0xBA, + (byte)0xBC, (byte)0x23, (byte)0x15, (byte)0xDC, + (byte)0x86, (byte)0x7C, (byte)0xB6, (byte)0x89, + (byte)0x25, (byte)0x25, (byte)0xCD, (byte)0x4A, + (byte)0x9B, (byte)0xCE, (byte)0xF4, (byte)0xAE, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x26, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x4B, + (byte)0x5E, (byte)0x05, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x08, (byte)0xE6, (byte)0xB0, + (byte)0x07, (byte)0xA8, (byte)0x5B, (byte)0xF8, + (byte)0x73, (byte)0xAD, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x2E, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x4B, (byte)0x5E, (byte)0x05, + (byte)0x00, (byte)0x11, (byte)0x00, (byte)0x10, + (byte)0xEA, (byte)0xF5, (byte)0xA8, (byte)0x36, + (byte)0xA5, (byte)0x3E, (byte)0x5F, (byte)0x5C, + (byte)0x26, (byte)0xE9, (byte)0xDD, (byte)0x8B, + (byte)0x8C, (byte)0xE8, (byte)0x92, (byte)0x9C, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x3E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x4B, + (byte)0x5E, (byte)0x05, (byte)0x00, (byte)0x12, + (byte)0x00, (byte)0x20, (byte)0x68, (byte)0xBE, + (byte)0xD4, (byte)0x17, (byte)0x3A, (byte)0x06, + (byte)0xE0, (byte)0x0C, (byte)0x62, (byte)0x11, + (byte)0xB7, (byte)0x53, (byte)0x1B, (byte)0x3E, + (byte)0xB2, (byte)0x6B, (byte)0x0D, (byte)0x48, + (byte)0xD8, (byte)0x52, (byte)0x5A, (byte)0x4C, + (byte)0xBE, (byte)0x24, (byte)0xBB, (byte)0x3D, + (byte)0xC1, (byte)0x74, (byte)0x69, (byte)0xDA, + (byte)0x34, (byte)0x98, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x51, (byte)0x27, (byte)0x03, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x08, + (byte)0xE6, (byte)0xB0, (byte)0x07, (byte)0xA8, + (byte)0x5B, (byte)0xF8, (byte)0x73, (byte)0xAD, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x2E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x51, + (byte)0x27, (byte)0x03, (byte)0x00, (byte)0x11, + (byte)0x00, (byte)0x10, (byte)0xEA, (byte)0xF5, + (byte)0xA8, (byte)0x36, (byte)0xA5, (byte)0x3E, + (byte)0x5F, (byte)0x5C, (byte)0x26, (byte)0xE9, + (byte)0xDD, (byte)0x8B, (byte)0x8C, (byte)0xE8, + (byte)0x92, (byte)0x9C, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x3E, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x51, (byte)0x27, (byte)0x03, + (byte)0x00, (byte)0x12, (byte)0x00, (byte)0x20, + (byte)0x68, (byte)0xBE, (byte)0xD4, (byte)0x17, + (byte)0x3A, (byte)0x06, (byte)0xE0, (byte)0x0C, + (byte)0x62, (byte)0x11, (byte)0xB7, (byte)0x53, + (byte)0x1B, (byte)0x3E, (byte)0xB2, (byte)0x6B, + (byte)0x0D, (byte)0x48, (byte)0xD8, (byte)0x52, + (byte)0x5A, (byte)0x4C, (byte)0xBE, (byte)0x24, + (byte)0xBB, (byte)0x3D, (byte)0xC1, (byte)0x74, + (byte)0x69, (byte)0xDA, (byte)0x34, (byte)0x98, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x26, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x68, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x54, + (byte)0xC7, (byte)0x01, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x08, (byte)0x85, (byte)0x5B, + (byte)0xE3, (byte)0x13, (byte)0x3E, (byte)0xF8, + (byte)0x76, (byte)0xEC, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x2E, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x68, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x54, (byte)0xC7, (byte)0x01, + (byte)0x00, (byte)0x11, (byte)0x00, (byte)0x10, + (byte)0xEC, (byte)0xCC, (byte)0x16, (byte)0xCD, + (byte)0xE8, (byte)0x51, (byte)0x46, (byte)0x4C, + (byte)0x1B, (byte)0x57, (byte)0xAE, (byte)0x19, + (byte)0xC3, (byte)0xD2, (byte)0x55, (byte)0x1B, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x3E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x68, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x54, + (byte)0xC7, (byte)0x01, (byte)0x00, (byte)0x12, + (byte)0x00, (byte)0x20, (byte)0xAE, (byte)0xBA, + (byte)0xCB, (byte)0xF5, (byte)0xA8, (byte)0x09, + (byte)0xC1, (byte)0xB0, (byte)0x2C, (byte)0x2A, + (byte)0x3D, (byte)0x96, (byte)0x2C, (byte)0x2D, + (byte)0xF5, (byte)0xFE, (byte)0x65, (byte)0xEC, + (byte)0x75, (byte)0x72, (byte)0x5B, (byte)0x46, + (byte)0x84, (byte)0xD7, (byte)0x49, (byte)0x3E, + (byte)0xF2, (byte)0x27, (byte)0x32, (byte)0x69, + (byte)0x75, (byte)0x9B, + }; + System.setProperty("java.security.krb5.conf", + new File(System.getProperty("test.src"), + "../krb5.conf").getAbsolutePath()); + FileOutputStream fout = new FileOutputStream("kt"); + fout.write(kt); + fout.close(); + KeyTab ktab = KeyTab.getInstance("kt"); + PrincipalName pn = new PrincipalName("me@MAD.LOCAL"); + EncryptionKey[] keys = ktab.readServiceKeys(pn); + if (keys[0].getKeyVersionNumber() != 5) { + throw new Exception("Highest not first"); + } + if (ktab.readServiceKey(pn).getKeyVersionNumber() != 5) { + throw new Exception("Highest not chosen"); + } + new File("kt").delete(); + } +}