Merge
This commit is contained in:
commit
ffe5156969
@ -1942,6 +1942,10 @@ public final class System {
|
||||
* the application classpath or modulepath.
|
||||
*/
|
||||
private static void initPhase3() {
|
||||
// Initialize publicLookup early, to avoid bootstrapping circularities
|
||||
// with security manager using java.lang.invoke infrastructure.
|
||||
java.lang.invoke.MethodHandles.publicLookup();
|
||||
|
||||
// set security manager
|
||||
String cn = System.getProperty("java.security.manager");
|
||||
if (cn != null) {
|
||||
|
@ -2204,15 +2204,7 @@ return mh1;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> PUBLIC_LOOKUP_CLASS;
|
||||
static {
|
||||
PrivilegedAction<Class<?>> pa = new PrivilegedAction<Class<?>>() {
|
||||
public Class<?> run() {
|
||||
return createClass();
|
||||
}
|
||||
};
|
||||
PUBLIC_LOOKUP_CLASS = AccessController.doPrivileged(pa);
|
||||
}
|
||||
private static final Class<?> PUBLIC_LOOKUP_CLASS = createClass();
|
||||
|
||||
/**
|
||||
* Lookup that is trusted minimally. It can only be used to create
|
||||
|
@ -1733,41 +1733,32 @@ public final class StringConcatFactory {
|
||||
// no instantiation
|
||||
}
|
||||
|
||||
// This one is deliberately non-lambdified to optimize startup time:
|
||||
private static final Function<Class<?>, MethodHandle> MOST = new Function<Class<?>, MethodHandle>() {
|
||||
private static class StringifierMost extends ClassValue<MethodHandle> {
|
||||
@Override
|
||||
public MethodHandle apply(Class<?> cl) {
|
||||
MethodHandle mhObject = lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
|
||||
|
||||
// We need the additional conversion here, because String.valueOf(Object) may return null.
|
||||
// String conversion rules in Java state we need to produce "null" String in this case.
|
||||
// It can be easily done with applying valueOf the second time.
|
||||
MethodHandle mhObjectNoNulls = MethodHandles.filterReturnValue(mhObject,
|
||||
mhObject.asType(MethodType.methodType(String.class, String.class)));
|
||||
|
||||
protected MethodHandle computeValue(Class<?> cl) {
|
||||
if (cl == String.class) {
|
||||
return mhObject;
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
|
||||
} else if (cl == float.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
|
||||
} else if (cl == double.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
|
||||
} else if (!cl.isPrimitive()) {
|
||||
return mhObjectNoNulls;
|
||||
MethodHandle mhObject = lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
|
||||
|
||||
// We need the additional conversion here, because String.valueOf(Object) may return null.
|
||||
// String conversion rules in Java state we need to produce "null" String in this case.
|
||||
// It can be easily done with applying valueOf the second time.
|
||||
return MethodHandles.filterReturnValue(mhObject,
|
||||
mhObject.asType(MethodType.methodType(String.class, String.class)));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This one is deliberately non-lambdified to optimize startup time:
|
||||
private static final Function<Class<?>, MethodHandle> ANY = new Function<Class<?>, MethodHandle>() {
|
||||
private static class StringifierAny extends ClassValue<MethodHandle> {
|
||||
@Override
|
||||
public MethodHandle apply(Class<?> cl) {
|
||||
MethodHandle mh = MOST.apply(cl);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
|
||||
protected MethodHandle computeValue(Class<?> cl) {
|
||||
if (cl == byte.class || cl == short.class || cl == int.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, int.class);
|
||||
} else if (cl == boolean.class) {
|
||||
@ -1777,13 +1768,18 @@ public final class StringConcatFactory {
|
||||
} else if (cl == long.class) {
|
||||
return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, long.class);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown class: " + cl);
|
||||
MethodHandle mh = STRINGIFIERS_MOST.get(cl);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown class: " + cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final ConcurrentMap<Class<?>, MethodHandle> STRINGIFIERS_MOST = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentMap<Class<?>, MethodHandle> STRINGIFIERS_ANY = new ConcurrentHashMap<>();
|
||||
private static final ClassValue<MethodHandle> STRINGIFIERS_MOST = new StringifierMost();
|
||||
private static final ClassValue<MethodHandle> STRINGIFIERS_ANY = new StringifierAny();
|
||||
|
||||
/**
|
||||
* Returns a stringifier for references and floats/doubles only.
|
||||
@ -1793,7 +1789,7 @@ public final class StringConcatFactory {
|
||||
* @return stringifier; null, if not available
|
||||
*/
|
||||
static MethodHandle forMost(Class<?> t) {
|
||||
return STRINGIFIERS_MOST.computeIfAbsent(t, MOST);
|
||||
return STRINGIFIERS_MOST.get(t);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1803,7 +1799,7 @@ public final class StringConcatFactory {
|
||||
* @return stringifier
|
||||
*/
|
||||
static MethodHandle forAny(Class<?> t) {
|
||||
return STRINGIFIERS_ANY.computeIfAbsent(t, ANY);
|
||||
return STRINGIFIERS_ANY.get(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -92,9 +92,9 @@ import java.lang.NullPointerException; // for javadoc
|
||||
* URIs are:
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code http://java.sun.com/j2se/1.3/}<br>
|
||||
* {@code docs/guide/collections/designfaq.html#28}<br>
|
||||
* {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java}<br>
|
||||
* {@code http://example.com/languages/java/}<br>
|
||||
* {@code sample/a/index.html#28}<br>
|
||||
* {@code ../../demo/b/index.html}<br>
|
||||
* {@code file:///~/calendar}
|
||||
* </blockquote>
|
||||
*
|
||||
@ -178,28 +178,28 @@ import java.lang.NullPointerException; // for javadoc
|
||||
* normalized. The result, for example, of resolving
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code docs/guide/collections/designfaq.html#28}
|
||||
* {@code sample/a/index.html#28}
|
||||
*
|
||||
* (1)
|
||||
* </blockquote>
|
||||
*
|
||||
* against the base URI {@code http://java.sun.com/j2se/1.3/} is the result
|
||||
* against the base URI {@code http://example.com/languages/java/} is the result
|
||||
* URI
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28}
|
||||
* {@code http://example.com/languages/java/sample/a/index.html#28}
|
||||
* </blockquote>
|
||||
*
|
||||
* Resolving the relative URI
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java} (2)
|
||||
* {@code ../../demo/b/index.html} (2)
|
||||
* </blockquote>
|
||||
*
|
||||
* against this result yields, in turn,
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code http://java.sun.com/j2se/1.3/demo/jfc/SwingSet2/src/SwingSet2.java}
|
||||
* {@code http://example.com/languages/java/demo/b/index.html}
|
||||
* </blockquote>
|
||||
*
|
||||
* Resolution of both absolute and relative URIs, and of both absolute and
|
||||
@ -210,7 +210,7 @@ import java.lang.NullPointerException; // for javadoc
|
||||
* URI
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code demo/jfc/SwingSet2/src/SwingSet2.java}
|
||||
* {@code demo/b/index.html}
|
||||
* </blockquote>
|
||||
*
|
||||
* <p> <i>Relativization</i>, finally, is the inverse of resolution: For any
|
||||
@ -226,16 +226,16 @@ import java.lang.NullPointerException; // for javadoc
|
||||
* possible. For example, relativizing the URI
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code http://docs.oracle.com/javase/1.3/docs/guide/index.html}
|
||||
* {@code http://example.com/languages/java/sample/a/index.html#28}
|
||||
* </blockquote>
|
||||
*
|
||||
* against the base URI
|
||||
*
|
||||
* <blockquote>
|
||||
* {@code http://java.sun.com/j2se/1.3}
|
||||
* {@code http://example.com/languages/java/}
|
||||
* </blockquote>
|
||||
*
|
||||
* yields the relative URI {@code docs/guide/index.html}.
|
||||
* yields the relative URI {@code sample/a/index.html#28}.
|
||||
*
|
||||
*
|
||||
* <h4> Character categories </h4>
|
||||
|
@ -33,6 +33,7 @@ package java.security;
|
||||
* can be passed to those implementations that support them.
|
||||
*
|
||||
* @see DrbgParameters
|
||||
* @since 9
|
||||
*/
|
||||
public interface SecureRandomParameters {
|
||||
}
|
||||
|
@ -2858,6 +2858,8 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* @param range a language range
|
||||
* @throws NullPointerException if the given {@code range} is
|
||||
* {@code null}
|
||||
* @throws IllegalArgumentException if the given {@code range} does not
|
||||
* comply with the syntax of the language range mentioned in RFC 4647
|
||||
*/
|
||||
public LanguageRange(String range) {
|
||||
this(range, MAX_WEIGHT);
|
||||
@ -2873,8 +2875,10 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* {@code MAX_WEIGHT}
|
||||
* @throws NullPointerException if the given {@code range} is
|
||||
* {@code null}
|
||||
* @throws IllegalArgumentException if the given {@code weight} is less
|
||||
* than {@code MIN_WEIGHT} or greater than {@code MAX_WEIGHT}
|
||||
* @throws IllegalArgumentException if the given {@code range} does not
|
||||
* comply with the syntax of the language range mentioned in RFC 4647
|
||||
* or if the given {@code weight} is less than {@code MIN_WEIGHT}
|
||||
* or greater than {@code MAX_WEIGHT}
|
||||
*/
|
||||
public LanguageRange(String range, double weight) {
|
||||
if (range == null) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -118,16 +118,22 @@ public class AnnotationType {
|
||||
members = new HashMap<>(methods.length+1, 1.0f);
|
||||
|
||||
for (Method method : methods) {
|
||||
if (method.getParameterTypes().length != 0)
|
||||
throw new IllegalArgumentException(method + " has params");
|
||||
String name = method.getName();
|
||||
Class<?> type = method.getReturnType();
|
||||
memberTypes.put(name, invocationHandlerReturnType(type));
|
||||
members.put(name, method);
|
||||
if (Modifier.isPublic(method.getModifiers()) &&
|
||||
Modifier.isAbstract(method.getModifiers()) &&
|
||||
!method.isSynthetic()) {
|
||||
if (method.getParameterTypes().length != 0) {
|
||||
throw new IllegalArgumentException(method + " has params");
|
||||
}
|
||||
String name = method.getName();
|
||||
Class<?> type = method.getReturnType();
|
||||
memberTypes.put(name, invocationHandlerReturnType(type));
|
||||
members.put(name, method);
|
||||
|
||||
Object defaultValue = method.getDefaultValue();
|
||||
if (defaultValue != null)
|
||||
memberDefaults.put(name, defaultValue);
|
||||
Object defaultValue = method.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
memberDefaults.put(name, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize retention, & inherited fields. Special treatment
|
||||
|
@ -33,12 +33,13 @@ import java.util.Objects;
|
||||
import static java.security.DrbgParameters.Capability.*;
|
||||
|
||||
/**
|
||||
* The abstract base class for all DRBGs.
|
||||
* The abstract base class for all DRBGs. It is used as {@link DRBG#impl}.
|
||||
* <p>
|
||||
* This class creates 5 new abstract methods. 3 are defined by the SP800-90A:
|
||||
* This class has 5 abstract methods. 3 are defined by SP800-90A:
|
||||
* <ol>
|
||||
* <li>{@link #generateAlgorithm(byte[], byte[])}
|
||||
* <li>{@link #reseedAlgorithm(byte[], byte[])} (might not be supported)
|
||||
* <li>{@link #reseedAlgorithm(byte[], byte[])} (In fact this is not an
|
||||
* abstract method, but any DRBG supporting reseeding must override it.)
|
||||
* <li>{@link #instantiateAlgorithm(byte[])}
|
||||
* </ol>
|
||||
* and 2 for implementation purpose:
|
||||
@ -46,18 +47,19 @@ import static java.security.DrbgParameters.Capability.*;
|
||||
* <li>{@link #initEngine()}
|
||||
* <li>{@link #chooseAlgorithmAndStrength}
|
||||
* </ol>
|
||||
* All existing {@link SecureRandomSpi} methods are implemented based on the
|
||||
* methods above as final. The initialization process is divided into 2 phases:
|
||||
* configuration is eagerly called to set up parameters, and instantiation
|
||||
* is lazily called only when nextBytes or reseed is called.
|
||||
* Although this class is not a child class of {@link SecureRandomSpi}, it
|
||||
* implements all abstract methods there as final.
|
||||
* <p>
|
||||
* The initialization process of a DRBG is divided into 2 phases:
|
||||
* {@link #configure configuration} is eagerly called to set up parameters,
|
||||
* and {@link #instantiateIfNecessary instantiation} is lazily called only
|
||||
* when nextBytes or reseed is called.
|
||||
* <p>
|
||||
* SecureRandom methods like reseed and nextBytes are not thread-safe.
|
||||
* An implementation is required to protect shared access to instantiate states
|
||||
* (instantiated, nonce) and DRBG states (v, c, key, reseedCounter).
|
||||
* (instantiated, nonce) and DRBG states (v, c, key, reseedCounter, etc).
|
||||
*/
|
||||
public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
public abstract class AbstractDrbg {
|
||||
|
||||
/**
|
||||
* This field is not null if {@code -Djava.security.debug=securerandom} is
|
||||
@ -69,7 +71,7 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
|
||||
// Common working status
|
||||
|
||||
private transient boolean instantiated = false;
|
||||
private boolean instantiated = false;
|
||||
|
||||
/**
|
||||
* Reseed counter of a DRBG instance. A mechanism should increment it
|
||||
@ -78,7 +80,7 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
*
|
||||
* Volatile, will be used in a double checked locking.
|
||||
*/
|
||||
protected transient volatile int reseedCounter = 0;
|
||||
protected volatile int reseedCounter = 0;
|
||||
|
||||
// Mech features. If not same as below, must be redefined in constructor.
|
||||
|
||||
@ -170,7 +172,7 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
/**
|
||||
* Algorithm used by this instance (SHA-512 or AES-256). Must be assigned
|
||||
* in {@link #chooseAlgorithmAndStrength}. This field is used in
|
||||
* {@link #toString()} and {@link DRBG#algorithmName}.
|
||||
* {@link #toString()}.
|
||||
*/
|
||||
protected String algorithm;
|
||||
|
||||
@ -217,7 +219,7 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
* After instantiation, this field is not null. Do not modify it
|
||||
* in a mechanism.
|
||||
*/
|
||||
protected transient byte[] nonce;
|
||||
protected byte[] nonce;
|
||||
|
||||
/**
|
||||
* Requested nonce in {@link MoreDrbgParameters}. If set to null,
|
||||
@ -237,7 +239,7 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
* {@link #configure(SecureRandomParameters)}. This field
|
||||
* can be null. {@link #getEntropyInput} will take care of null check.
|
||||
*/
|
||||
private transient EntropySource es;
|
||||
private EntropySource es;
|
||||
|
||||
// Five abstract methods for SP 800-90A DRBG
|
||||
|
||||
@ -286,10 +288,7 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
|
||||
/**
|
||||
* Initiates security engines ({@code MessageDigest}, {@code Mac},
|
||||
* or {@code Cipher}). Must be called in deserialization. Please note
|
||||
* that before instantiation the algorithm might not be available yet.
|
||||
* In this case, just return and this method will be called
|
||||
* automatically at instantiation.
|
||||
* or {@code Cipher}). This method is called during instantiation.
|
||||
*/
|
||||
protected abstract void initEngine();
|
||||
|
||||
@ -331,13 +330,11 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
|
||||
// SecureRandomSpi methods taken care of here. All final.
|
||||
|
||||
@Override
|
||||
protected final void engineNextBytes(byte[] result) {
|
||||
engineNextBytes(result, DrbgParameters.nextBytes(
|
||||
-1, predictionResistanceFlag, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void engineNextBytes(
|
||||
byte[] result, SecureRandomParameters params) {
|
||||
|
||||
@ -402,7 +399,6 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void engineReseed(SecureRandomParameters params) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "reseed with params");
|
||||
@ -454,7 +450,6 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
* @param numBytes the number of seed bytes to generate.
|
||||
* @return the seed bytes.
|
||||
*/
|
||||
@Override
|
||||
public final byte[] engineGenerateSeed(int numBytes) {
|
||||
byte[] b = new byte[numBytes];
|
||||
SeedGenerator.generateSeed(b);
|
||||
@ -469,7 +464,6 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
*
|
||||
* @param input the seed
|
||||
*/
|
||||
@Override
|
||||
public final synchronized void engineSetSeed(byte[] input) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "setSeed");
|
||||
@ -598,7 +592,6 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
*
|
||||
* @return the curent configuration
|
||||
*/
|
||||
@Override
|
||||
protected SecureRandomParameters engineGetParameters() {
|
||||
// Or read from variable.
|
||||
return DrbgParameters.instantiation(
|
||||
@ -631,7 +624,8 @@ public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
this.es = m.es;
|
||||
this.requestedAlgorithm = m.algorithm;
|
||||
this.usedf = m.usedf;
|
||||
params = m.config;
|
||||
params = DrbgParameters.instantiation(m.strength,
|
||||
m.capability, m.personalizationString);
|
||||
}
|
||||
if (params != null) {
|
||||
if (params instanceof DrbgParameters.Instantiation) {
|
||||
|
@ -32,8 +32,6 @@ import java.util.Locale;
|
||||
|
||||
public abstract class AbstractHashDrbg extends AbstractDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
protected int outLen;
|
||||
protected int seedLen;
|
||||
|
||||
|
@ -28,14 +28,12 @@ package sun.security.provider;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.security.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public class CtrDrbg extends AbstractDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
private static final int AES_LIMIT;
|
||||
|
||||
static {
|
||||
@ -47,7 +45,7 @@ public class CtrDrbg extends AbstractDrbg {
|
||||
}
|
||||
}
|
||||
|
||||
private transient Cipher cipher;
|
||||
private Cipher cipher;
|
||||
|
||||
private String cipherAlg;
|
||||
private String keyAlg;
|
||||
@ -57,8 +55,8 @@ public class CtrDrbg extends AbstractDrbg {
|
||||
private int keyLen;
|
||||
private int seedLen;
|
||||
|
||||
private transient byte[] v;
|
||||
private transient byte[] k;
|
||||
private byte[] v;
|
||||
private byte[] k;
|
||||
|
||||
public CtrDrbg(SecureRandomParameters params) {
|
||||
mechName = "CTR_DRBG";
|
||||
@ -165,7 +163,7 @@ public class CtrDrbg extends AbstractDrbg {
|
||||
protected void initEngine() {
|
||||
try {
|
||||
/*
|
||||
* Use the local SUN implementation to avoid native
|
||||
* Use the local SunJCE implementation to avoid native
|
||||
* performance overhead.
|
||||
*/
|
||||
cipher = Cipher.getInstance(cipherAlg, "SunJCE");
|
||||
@ -463,12 +461,6 @@ public class CtrDrbg extends AbstractDrbg {
|
||||
// Step 8. Return
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
initEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + ","
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.DrbgParameters;
|
||||
import java.security.PrivilegedAction;
|
||||
@ -61,11 +62,12 @@ public final class DRBG extends SecureRandomSpi {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
private final AbstractDrbg impl;
|
||||
private transient AbstractDrbg impl;
|
||||
|
||||
private final String mechName;
|
||||
|
||||
private final String algorithmName;
|
||||
/**
|
||||
* @serial
|
||||
*/
|
||||
private final MoreDrbgParameters mdp;
|
||||
|
||||
public DRBG(SecureRandomParameters params) {
|
||||
|
||||
@ -91,7 +93,7 @@ public final class DRBG extends SecureRandomSpi {
|
||||
// Can be configured with a security property
|
||||
|
||||
String config = AccessController.doPrivileged((PrivilegedAction<String>)
|
||||
() -> Security.getProperty(PROP_NAME));
|
||||
() -> Security.getProperty(PROP_NAME));
|
||||
|
||||
if (config != null && !config.isEmpty()) {
|
||||
for (String part : config.split(",")) {
|
||||
@ -151,8 +153,9 @@ public final class DRBG extends SecureRandomSpi {
|
||||
if (params != null) {
|
||||
// MoreDrbgParameters is used for testing.
|
||||
if (params instanceof MoreDrbgParameters) {
|
||||
MoreDrbgParameters m = (MoreDrbgParameters)params;
|
||||
params = m.config;
|
||||
MoreDrbgParameters m = (MoreDrbgParameters) params;
|
||||
params = DrbgParameters.instantiation(m.strength,
|
||||
m.capability, m.personalizationString);
|
||||
|
||||
// No need to check null for es and nonce, they are still null
|
||||
es = m.es;
|
||||
@ -197,26 +200,27 @@ public final class DRBG extends SecureRandomSpi {
|
||||
usedf = true;
|
||||
}
|
||||
|
||||
MoreDrbgParameters m = new MoreDrbgParameters(
|
||||
mdp = new MoreDrbgParameters(
|
||||
es, mech, algorithm, nonce, usedf,
|
||||
DrbgParameters.instantiation(strength, cap, ps));
|
||||
|
||||
switch (mech.toLowerCase(Locale.ROOT)) {
|
||||
createImpl();
|
||||
}
|
||||
|
||||
private void createImpl() {
|
||||
switch (mdp.mech.toLowerCase(Locale.ROOT)) {
|
||||
case "hash_drbg":
|
||||
impl = new HashDrbg(m);
|
||||
impl = new HashDrbg(mdp);
|
||||
break;
|
||||
case "hmac_drbg":
|
||||
impl = new HmacDrbg(m);
|
||||
impl = new HmacDrbg(mdp);
|
||||
break;
|
||||
case "ctr_drbg":
|
||||
impl = new CtrDrbg(m);
|
||||
impl = new CtrDrbg(mdp);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported mech: " + mech);
|
||||
throw new IllegalArgumentException("Unsupported mech: " + mdp.mech);
|
||||
}
|
||||
|
||||
mechName = mech;
|
||||
algorithmName = impl.algorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -268,4 +272,13 @@ public final class DRBG extends SecureRandomSpi {
|
||||
+ " cannot be provided more than once in " + PROP_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
if (mdp.mech == null) {
|
||||
throw new IllegalArgumentException("Input data is corrupted");
|
||||
}
|
||||
createImpl();
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
@ -36,15 +35,13 @@ import java.util.Arrays;
|
||||
|
||||
public class HashDrbg extends AbstractHashDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
private static final byte[] ZERO = new byte[1];
|
||||
private static final byte[] ONE = new byte[]{1};
|
||||
|
||||
private transient MessageDigest digest;
|
||||
private MessageDigest digest;
|
||||
|
||||
private transient byte[] v;
|
||||
private transient byte[] c;
|
||||
private byte[] v;
|
||||
private byte[] c;
|
||||
|
||||
public HashDrbg(SecureRandomParameters params) {
|
||||
mechName = "Hash_DRBG";
|
||||
@ -267,10 +264,4 @@ public class HashDrbg extends AbstractHashDrbg {
|
||||
// Step 5: No need to truncate
|
||||
// Step 6: Return
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
initEngine();
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ package sun.security.provider;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
@ -36,14 +35,12 @@ import java.util.Arrays;
|
||||
|
||||
public class HmacDrbg extends AbstractHashDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
private transient Mac mac;
|
||||
private Mac mac;
|
||||
|
||||
private String macAlg;
|
||||
|
||||
private transient byte[] v;
|
||||
private transient byte[] k;
|
||||
private byte[] v;
|
||||
private byte[] k;
|
||||
|
||||
public HmacDrbg(SecureRandomParameters params) {
|
||||
mechName = "HMAC_DRBG";
|
||||
@ -101,6 +98,10 @@ public class HmacDrbg extends AbstractHashDrbg {
|
||||
protected void initEngine() {
|
||||
macAlg = "HmacSHA" + algorithm.substring(4);
|
||||
try {
|
||||
/*
|
||||
* Use the local SunJCE implementation to avoid native
|
||||
* performance overhead.
|
||||
*/
|
||||
mac = Mac.getInstance(macAlg, "SunJCE");
|
||||
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
|
||||
// Fallback to any available.
|
||||
@ -194,10 +195,4 @@ public class HmacDrbg extends AbstractHashDrbg {
|
||||
|
||||
// Step 8. Return
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
initEngine();
|
||||
}
|
||||
}
|
||||
|
@ -25,20 +25,30 @@
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.DrbgParameters;
|
||||
import java.security.SecureRandomParameters;
|
||||
|
||||
/**
|
||||
* Extra non-standard parameters that can be used by DRBGs.
|
||||
* Exported and non-exported parameters that can be used by DRBGs.
|
||||
*/
|
||||
public class MoreDrbgParameters implements SecureRandomParameters {
|
||||
public class MoreDrbgParameters implements SecureRandomParameters, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
final transient EntropySource es;
|
||||
|
||||
final String mech;
|
||||
final String algorithm;
|
||||
final EntropySource es;
|
||||
final byte[] nonce;
|
||||
final boolean usedf;
|
||||
final DrbgParameters.Instantiation config;
|
||||
final int strength;
|
||||
final DrbgParameters.Capability capability;
|
||||
|
||||
// The following 2 fields will be reassigned in readObject and
|
||||
// thus cannot be final
|
||||
byte[] nonce;
|
||||
byte[] personalizationString;
|
||||
|
||||
/**
|
||||
* Creates a new {@code MoreDrbgParameters} object.
|
||||
@ -61,13 +71,31 @@ public class MoreDrbgParameters implements SecureRandomParameters {
|
||||
this.mech = mech;
|
||||
this.algorithm = algorithm;
|
||||
this.es = es;
|
||||
this.nonce = nonce;
|
||||
this.nonce = (nonce == null) ? null : nonce.clone();
|
||||
this.usedf = usedf;
|
||||
this.config = config;
|
||||
|
||||
this.strength = config.getStrength();
|
||||
this.capability = config.getCapability();
|
||||
this.personalizationString = config.getPersonalizationString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mech + "," + algorithm + "," + usedf + "," + config;
|
||||
return mech + "," + algorithm + "," + usedf + "," + strength
|
||||
+ "," + capability + "," + personalizationString;
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
if (nonce != null) {
|
||||
nonce = nonce.clone();
|
||||
}
|
||||
if (personalizationString != null) {
|
||||
personalizationString = personalizationString.clone();
|
||||
}
|
||||
if (capability == null) {
|
||||
throw new IllegalArgumentException("Input data is corrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -347,7 +347,7 @@ class SSLServerSocketImpl extends SSLServerSocket
|
||||
SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
|
||||
enabledCipherSuites, clientAuthType, enableSessionCreation,
|
||||
enabledProtocols, identificationProtocol, algorithmConstraints,
|
||||
sniMatchers, preferLocalCipherSuites);
|
||||
sniMatchers, preferLocalCipherSuites, applicationProtocols);
|
||||
|
||||
implAccept(s);
|
||||
s.doneConnect();
|
||||
|
@ -497,7 +497,8 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
String identificationProtocol,
|
||||
AlgorithmConstraints algorithmConstraints,
|
||||
Collection<SNIMatcher> sniMatchers,
|
||||
boolean preferLocalCipherSuites) throws IOException {
|
||||
boolean preferLocalCipherSuites,
|
||||
String[] applicationProtocols) throws IOException {
|
||||
|
||||
super();
|
||||
doClientAuth = clientAuth;
|
||||
@ -506,6 +507,7 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
this.algorithmConstraints = algorithmConstraints;
|
||||
this.sniMatchers = sniMatchers;
|
||||
this.preferLocalCipherSuites = preferLocalCipherSuites;
|
||||
this.applicationProtocols = applicationProtocols;
|
||||
init(context, serverMode);
|
||||
|
||||
/*
|
||||
|
@ -206,7 +206,7 @@ public final class Main {
|
||||
IMPORTKEYSTORE("Imports.one.or.all.entries.from.another.keystore",
|
||||
SRCKEYSTORE, DESTKEYSTORE, SRCSTORETYPE,
|
||||
DESTSTORETYPE, SRCSTOREPASS, DESTSTOREPASS,
|
||||
SRCPROTECTED, SRCPROVIDERNAME, DESTPROVIDERNAME,
|
||||
SRCPROTECTED, DESTPROTECTED, SRCPROVIDERNAME, DESTPROVIDERNAME,
|
||||
SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS,
|
||||
NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH,
|
||||
V),
|
||||
|
@ -86,7 +86,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
}
|
||||
};
|
||||
transmitter = new WSTransmitter(executor, channel, errorHandler);
|
||||
transmitter = new WSTransmitter(this, executor, channel, errorHandler);
|
||||
receiver = new WSReceiver(this.listener, this, executor, channel);
|
||||
}
|
||||
|
||||
@ -95,12 +95,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendText(ByteBuffer message, boolean isLast) {
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendText(CharSequence message, boolean isLast) {
|
||||
public CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast) {
|
||||
requireNonNull(message, "message");
|
||||
synchronized (stateLock) {
|
||||
checkState();
|
||||
@ -109,7 +104,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendText(Stream<? extends CharSequence> message) {
|
||||
public CompletableFuture<WebSocket> sendText(Stream<? extends CharSequence> message) {
|
||||
requireNonNull(message, "message");
|
||||
synchronized (stateLock) {
|
||||
checkState();
|
||||
@ -118,7 +113,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendBinary(ByteBuffer message, boolean isLast) {
|
||||
public CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast) {
|
||||
requireNonNull(message, "message");
|
||||
synchronized (stateLock) {
|
||||
checkState();
|
||||
@ -127,7 +122,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendPing(ByteBuffer message) {
|
||||
public CompletableFuture<WebSocket> sendPing(ByteBuffer message) {
|
||||
requireNonNull(message, "message");
|
||||
synchronized (stateLock) {
|
||||
checkState();
|
||||
@ -136,7 +131,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendPong(ByteBuffer message) {
|
||||
public CompletableFuture<WebSocket> sendPong(ByteBuffer message) {
|
||||
requireNonNull(message, "message");
|
||||
synchronized (stateLock) {
|
||||
checkState();
|
||||
@ -145,7 +140,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendClose(CloseCode code, CharSequence reason) {
|
||||
public CompletableFuture<WebSocket> sendClose(CloseCode code, CharSequence reason) {
|
||||
requireNonNull(code, "code");
|
||||
requireNonNull(reason, "reason");
|
||||
synchronized (stateLock) {
|
||||
@ -154,13 +149,13 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendClose() {
|
||||
public CompletableFuture<WebSocket> sendClose() {
|
||||
synchronized (stateLock) {
|
||||
return doSendClose(() -> transmitter.sendClose());
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> doSendClose(Supplier<CompletableFuture<Void>> s) {
|
||||
private CompletableFuture<WebSocket> doSendClose(Supplier<CompletableFuture<WebSocket>> s) {
|
||||
checkState();
|
||||
boolean closeChannel = false;
|
||||
synchronized (stateLock) {
|
||||
@ -170,7 +165,7 @@ final class WS implements WebSocket {
|
||||
tryChangeState(State.CLOSED_LOCALLY);
|
||||
}
|
||||
}
|
||||
CompletableFuture<Void> sent = s.get();
|
||||
CompletableFuture<WebSocket> sent = s.get();
|
||||
if (closeChannel) {
|
||||
sent.whenComplete((v, t) -> {
|
||||
try {
|
||||
@ -239,7 +234,7 @@ final class WS implements WebSocket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onText(WebSocket webSocket, Text message,
|
||||
public CompletionStage<?> onText(WebSocket webSocket, CharSequence message,
|
||||
MessagePart part) {
|
||||
synchronized (visibilityLock) {
|
||||
return listener.onText(webSocket, message, part);
|
||||
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.net.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
final class WSDisposableText implements WebSocket.Text, WSDisposable {
|
||||
|
||||
private final WSShared<CharBuffer> text;
|
||||
|
||||
WSDisposableText(WSShared<CharBuffer> text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return text.buffer().length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return text.buffer().charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return text.buffer().subSequence(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer asByteBuffer() {
|
||||
throw new UnsupportedOperationException("To be removed from the API");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text.buffer().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
text.dispose();
|
||||
}
|
||||
}
|
@ -214,7 +214,7 @@ final class WSFrameConsumer implements WSFrame.Consumer {
|
||||
if (!(binaryNonEmpty && !textData.hasRemaining())) {
|
||||
// If there's a binary data, that result in no text, then we
|
||||
// don't deliver anything
|
||||
output.onText(part, new WSDisposableText(textData));
|
||||
output.onText(part, textData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,11 @@ package java.net.http;
|
||||
import java.net.http.WebSocket.CloseCode;
|
||||
import java.net.http.WebSocket.MessagePart;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
interface WSMessageConsumer {
|
||||
|
||||
void onText(MessagePart part, WSDisposableText data);
|
||||
void onText(MessagePart part, WSShared<CharBuffer> data);
|
||||
|
||||
void onBinary(MessagePart part, WSShared<ByteBuffer> data);
|
||||
|
||||
|
@ -29,6 +29,7 @@ import java.io.UncheckedIOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.http.WebSocket.Listener;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
@ -169,11 +170,11 @@ final class WSReceiver {
|
||||
private final class MessageConsumer implements WSMessageConsumer {
|
||||
|
||||
@Override
|
||||
public void onText(WebSocket.MessagePart part, WSDisposableText data) {
|
||||
public void onText(WebSocket.MessagePart part, WSShared<CharBuffer> data) {
|
||||
decrementDemand();
|
||||
CompletionStage<?> cs;
|
||||
try {
|
||||
cs = listener.onText(webSocket, data, part);
|
||||
cs = listener.onText(webSocket, data.buffer(), part);
|
||||
} catch (Exception e) {
|
||||
closeExceptionally(new RuntimeException("onText threw an exception", e));
|
||||
return;
|
||||
|
@ -51,15 +51,17 @@ import static java.net.http.Pair.pair;
|
||||
*/
|
||||
final class WSTransmitter {
|
||||
|
||||
private final BlockingQueue<Pair<WSOutgoingMessage, CompletableFuture<Void>>>
|
||||
private final BlockingQueue<Pair<WSOutgoingMessage, CompletableFuture<WebSocket>>>
|
||||
backlog = new LinkedBlockingQueue<>();
|
||||
private final WSMessageSender sender;
|
||||
private final WSSignalHandler handler;
|
||||
private final WebSocket webSocket;
|
||||
private boolean previousMessageSent = true;
|
||||
private boolean canSendBinary = true;
|
||||
private boolean canSendText = true;
|
||||
|
||||
WSTransmitter(Executor executor, RawChannel channel, Consumer<Throwable> errorHandler) {
|
||||
WSTransmitter(WebSocket ws, Executor executor, RawChannel channel, Consumer<Throwable> errorHandler) {
|
||||
this.webSocket = ws;
|
||||
this.handler = new WSSignalHandler(executor, this::handleSignal);
|
||||
Consumer<Throwable> sendCompletion = (error) -> {
|
||||
synchronized (this) {
|
||||
@ -76,41 +78,41 @@ final class WSTransmitter {
|
||||
this.sender = new WSMessageSender(channel, sendCompletion);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendText(CharSequence message, boolean isLast) {
|
||||
CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast) {
|
||||
checkAndUpdateText(isLast);
|
||||
return acceptMessage(new Text(isLast, message));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendText(Stream<? extends CharSequence> message) {
|
||||
CompletableFuture<WebSocket> sendText(Stream<? extends CharSequence> message) {
|
||||
checkAndUpdateText(true);
|
||||
return acceptMessage(new StreamedText(message));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendBinary(ByteBuffer message, boolean isLast) {
|
||||
CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast) {
|
||||
checkAndUpdateBinary(isLast);
|
||||
return acceptMessage(new Binary(isLast, message));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendPing(ByteBuffer message) {
|
||||
CompletableFuture<WebSocket> sendPing(ByteBuffer message) {
|
||||
checkSize(message.remaining(), 125);
|
||||
return acceptMessage(new Ping(message));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendPong(ByteBuffer message) {
|
||||
CompletableFuture<WebSocket> sendPong(ByteBuffer message) {
|
||||
checkSize(message.remaining(), 125);
|
||||
return acceptMessage(new Pong(message));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendClose(WebSocket.CloseCode code, CharSequence reason) {
|
||||
CompletableFuture<WebSocket> sendClose(WebSocket.CloseCode code, CharSequence reason) {
|
||||
return acceptMessage(createCloseMessage(code, reason));
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sendClose() {
|
||||
CompletableFuture<WebSocket> sendClose() {
|
||||
return acceptMessage(new Close(ByteBuffer.allocate(0)));
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> acceptMessage(WSOutgoingMessage m) {
|
||||
CompletableFuture<Void> cf = new CompletableFuture<>();
|
||||
private CompletableFuture<WebSocket> acceptMessage(WSOutgoingMessage m) {
|
||||
CompletableFuture<WebSocket> cf = new CompletableFuture<>();
|
||||
synchronized (this) {
|
||||
backlog.offer(pair(m, cf));
|
||||
}
|
||||
@ -123,11 +125,11 @@ final class WSTransmitter {
|
||||
synchronized (this) {
|
||||
while (!backlog.isEmpty() && previousMessageSent) {
|
||||
previousMessageSent = false;
|
||||
Pair<WSOutgoingMessage, CompletableFuture<Void>> p = backlog.peek();
|
||||
Pair<WSOutgoingMessage, CompletableFuture<WebSocket>> p = backlog.peek();
|
||||
boolean sent = sender.trySendFully(p.first);
|
||||
if (sent) {
|
||||
backlog.remove();
|
||||
p.second.complete(null);
|
||||
p.second.complete(webSocket);
|
||||
previousMessageSent = true;
|
||||
}
|
||||
}
|
||||
|
@ -52,8 +52,8 @@ import java.util.stream.Stream;
|
||||
*
|
||||
* <p> Messages of type {@code X} are sent through the {@code WebSocket.sendX}
|
||||
* methods and received through {@link WebSocket.Listener}{@code .onX} methods
|
||||
* asynchronously. Each of the methods begins the operation and returns a {@link
|
||||
* CompletionStage} which completes when the operation has completed.
|
||||
* asynchronously. Each of the methods returns a {@link CompletionStage} which
|
||||
* completes when the operation has completed.
|
||||
*
|
||||
* <p> Messages are received only if {@linkplain #request(long) requested}.
|
||||
*
|
||||
@ -79,6 +79,9 @@ import java.util.stream.Stream;
|
||||
* or method of this type will cause a {@link NullPointerException
|
||||
* NullPointerException} to be thrown.
|
||||
*
|
||||
* @implNote The default implementation's methods do not block before returning
|
||||
* a {@code CompletableFuture}.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public interface WebSocket {
|
||||
@ -234,9 +237,9 @@ public interface WebSocket {
|
||||
/**
|
||||
* Builds a {@code WebSocket}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<WebSocket>}
|
||||
* which completes with the {@code WebSocket} when it is connected, or
|
||||
* completes exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally with the {@code WebSocket} when it is connected or completes
|
||||
* exceptionally if an error occurs.
|
||||
*
|
||||
* <p> {@code CompletableFuture} may complete exceptionally with the
|
||||
* following errors:
|
||||
@ -252,7 +255,7 @@ public interface WebSocket {
|
||||
* if the opening handshake fails
|
||||
* </ul>
|
||||
*
|
||||
* @return a {@code CompletableFuture} of {@code WebSocket}
|
||||
* @return a {@code CompletableFuture} with the {@code WebSocket}
|
||||
*/
|
||||
CompletableFuture<WebSocket> buildAsync();
|
||||
}
|
||||
@ -264,7 +267,7 @@ public interface WebSocket {
|
||||
* <ul>
|
||||
* <li> {@link #onOpen onOpen} <br>
|
||||
* This method is always the first to be invoked.
|
||||
* <li> {@link #onText(WebSocket, WebSocket.Text, WebSocket.MessagePart)
|
||||
* <li> {@link #onText(WebSocket, CharSequence, WebSocket.MessagePart)
|
||||
* onText}, {@link #onBinary(WebSocket, ByteBuffer, WebSocket.MessagePart)
|
||||
* onBinary}, {@link #onPing(WebSocket, ByteBuffer) onPing} and {@link
|
||||
* #onPong(WebSocket, ByteBuffer) onPong} <br>
|
||||
@ -375,6 +378,9 @@ public interface WebSocket {
|
||||
* @implSpec The default implementation {@linkplain WebSocket#request(long)
|
||||
* requests one more message}.
|
||||
*
|
||||
* @implNote This implementation passes only complete UTF-16 sequences
|
||||
* to the {@code onText} method.
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket
|
||||
* @param message
|
||||
@ -386,7 +392,7 @@ public interface WebSocket {
|
||||
* is done; or {@code null} if already done
|
||||
*/
|
||||
default CompletionStage<?> onText(WebSocket webSocket,
|
||||
Text message,
|
||||
CharSequence message,
|
||||
MessagePart part) {
|
||||
webSocket.request(1);
|
||||
return null;
|
||||
@ -596,59 +602,11 @@ public interface WebSocket {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a Text message with bytes from the given {@code ByteBuffer}.
|
||||
* Sends a Text message with characters from the given {@code CharSequence}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
*
|
||||
* <p> This message may be a partial UTF-8 sequence. However, the
|
||||
* concatenation of all messages through the last must be a whole UTF-8
|
||||
* sequence.
|
||||
*
|
||||
* <p> The {@code ByteBuffer} should not be modified until the returned
|
||||
* {@code CompletableFuture} completes (either normally or exceptionally).
|
||||
*
|
||||
* <p> The returned {@code CompletableFuture} can complete exceptionally
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation; or the
|
||||
* {@code WebSocket} closes while this operation is in progress;
|
||||
* or the {@code message} is a malformed UTF-8 sequence
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param isLast
|
||||
* {@code true} if this is the final part of the message,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been sent already
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalStateException
|
||||
* if a previous Binary message
|
||||
* was not sent with {@code isLast == true}
|
||||
*/
|
||||
CompletableFuture<Void> sendText(ByteBuffer message, boolean isLast);
|
||||
|
||||
/**
|
||||
* Sends a Text message with characters from the given {@code
|
||||
* CharSequence}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
*
|
||||
* <p> This message may be a partial UTF-16 sequence. However, the
|
||||
* concatenation of all messages through the last must be a whole UTF-16
|
||||
* sequence.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> The {@code CharSequence} should not be modified until the returned
|
||||
* {@code CompletableFuture} completes (either normally or exceptionally).
|
||||
@ -657,30 +615,30 @@ public interface WebSocket {
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation; or the
|
||||
* {@code WebSocket} closes while this operation is in progress;
|
||||
* or the {@code message} is a malformed UTF-16 sequence
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation;
|
||||
* or if a previous Binary message was not sent with {@code isLast == true}
|
||||
* </ul>
|
||||
*
|
||||
* @implNote This implementation does not accept partial UTF-16
|
||||
* sequences. In case such a sequence is passed, a returned {@code
|
||||
* CompletableFuture} completes exceptionally.
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param isLast
|
||||
* {@code true} if this is the final part of the message
|
||||
* {@code true} if this is the final part of the message,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalStateException
|
||||
* if a previous Binary message was not sent
|
||||
* with {@code isLast == true}
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code message} is a malformed (or an incomplete) UTF-16 sequence
|
||||
*/
|
||||
CompletableFuture<Void> sendText(CharSequence message, boolean isLast);
|
||||
CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast);
|
||||
|
||||
/**
|
||||
* Sends a whole Text message with characters from the given {@code
|
||||
@ -689,9 +647,9 @@ public interface WebSocket {
|
||||
* <p> This is a convenience method. For the general case, use {@link
|
||||
* #sendText(CharSequence, boolean)}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> The {@code CharSequence} should not be modified until the returned
|
||||
* {@code CompletableFuture} completes (either normally or exceptionally).
|
||||
@ -700,27 +658,23 @@ public interface WebSocket {
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation; or the
|
||||
* {@code WebSocket} closes while this operation is in progress;
|
||||
* or the message is a malformed UTF-16 sequence
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation;
|
||||
* or if a previous Binary message was not sent with {@code isLast == true}
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalStateException
|
||||
* if a previous Binary message was not sent
|
||||
* with {@code isLast == true}
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code message} is a malformed (or an incomplete) UTF-16 sequence
|
||||
*/
|
||||
default CompletableFuture<Void> sendText(CharSequence message) {
|
||||
default CompletableFuture<WebSocket> sendText(CharSequence message) {
|
||||
return sendText(message, true);
|
||||
}
|
||||
|
||||
@ -731,9 +685,9 @@ public interface WebSocket {
|
||||
* <p> This is a convenience method. For the general case use {@link
|
||||
* #sendText(CharSequence, boolean)}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> Streamed character sequences should not be modified until the
|
||||
* returned {@code CompletableFuture} completes (either normally or
|
||||
@ -743,41 +697,41 @@ public interface WebSocket {
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation; or the
|
||||
* {@code WebSocket} closes while this operation is in progress;
|
||||
* or the message is a malformed UTF-16 sequence
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation;
|
||||
* or if a previous Binary message was not sent with {@code isLast == true}
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalStateException
|
||||
* if a previous Binary message was not sent
|
||||
* with {@code isLast == true}
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code message} is a malformed (or an incomplete) UTF-16 sequence
|
||||
*/
|
||||
CompletableFuture<Void> sendText(Stream<? extends CharSequence> message);
|
||||
CompletableFuture<WebSocket> sendText(Stream<? extends CharSequence> message);
|
||||
|
||||
/**
|
||||
* Sends a Binary message with bytes from the given {@code ByteBuffer}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> The returned {@code CompletableFuture} can complete exceptionally
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation or the
|
||||
* {@code WebSocket} closes while this operation is in progress
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation;
|
||||
* or if a previous Text message was not sent with {@code isLast == true}
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
@ -786,33 +740,27 @@ public interface WebSocket {
|
||||
* {@code true} if this is the final part of the message,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalStateException
|
||||
* if a previous Text message was not sent
|
||||
* with {@code isLast == true}
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*/
|
||||
CompletableFuture<Void> sendBinary(ByteBuffer message, boolean isLast);
|
||||
CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast);
|
||||
|
||||
/**
|
||||
* Sends a Binary message with bytes from the given {@code byte[]}.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> The returned {@code CompletableFuture} can complete exceptionally
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation or the
|
||||
* {@code WebSocket} closes while this operation is in progress
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation;
|
||||
* or if a previous Text message was not sent with {@code isLast == true}
|
||||
* </ul>
|
||||
*
|
||||
* @implSpec This is equivalent to:
|
||||
@ -826,19 +774,9 @@ public interface WebSocket {
|
||||
* {@code true} if this is the final part of the message,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalStateException
|
||||
* if a previous Text message was not sent
|
||||
* with {@code isLast == true}
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*/
|
||||
default CompletableFuture<Void> sendBinary(byte[] message, boolean isLast) {
|
||||
default CompletableFuture<WebSocket> sendBinary(byte[] message, boolean isLast) {
|
||||
Objects.requireNonNull(message, "message");
|
||||
return sendBinary(ByteBuffer.wrap(message), isLast);
|
||||
}
|
||||
@ -846,9 +784,9 @@ public interface WebSocket {
|
||||
/**
|
||||
* Sends a Ping message.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> A Ping message may be sent or received by either client or server.
|
||||
* It may serve either as a keepalive or as a means to verify that the
|
||||
@ -861,32 +799,29 @@ public interface WebSocket {
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation or the
|
||||
* {@code WebSocket} closes while this operation is in progress
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code message.remaining() > 125}
|
||||
*/
|
||||
CompletableFuture<Void> sendPing(ByteBuffer message);
|
||||
CompletableFuture<WebSocket> sendPing(ByteBuffer message);
|
||||
|
||||
/**
|
||||
* Sends a Pong message.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> A Pong message may be unsolicited or may be sent in response to a
|
||||
* previously received Ping. In latter case the contents of the Pong is
|
||||
@ -899,32 +834,29 @@ public interface WebSocket {
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation or the
|
||||
* {@code WebSocket} closes while this operation is in progress
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code message.remaining() > 125}
|
||||
*/
|
||||
CompletableFuture<Void> sendPong(ByteBuffer message);
|
||||
CompletableFuture<WebSocket> sendPong(ByteBuffer message);
|
||||
|
||||
/**
|
||||
* Sends a Close message with the given close code and the reason.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> A Close message may consist of a close code and a reason for closing.
|
||||
* The reason must have a valid UTF-8 representation not longer than {@code
|
||||
@ -935,8 +867,11 @@ public interface WebSocket {
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation or the
|
||||
* {@code WebSocket} closes while this operation is in progress
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation
|
||||
* </ul>
|
||||
*
|
||||
* @param code
|
||||
@ -944,45 +879,35 @@ public interface WebSocket {
|
||||
* @param reason
|
||||
* the reason; can be empty
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @throws IllegalArgumentException
|
||||
* if the {@code reason} doesn't have a valid UTF-8
|
||||
* representation not longer than {@code 123} bytes
|
||||
* if {@code reason} doesn't have an UTF-8 representation not longer
|
||||
* than {@code 123} bytes
|
||||
*/
|
||||
CompletableFuture<Void> sendClose(CloseCode code, CharSequence reason);
|
||||
CompletableFuture<WebSocket> sendClose(CloseCode code, CharSequence reason);
|
||||
|
||||
/**
|
||||
* Sends an empty Close message.
|
||||
*
|
||||
* <p> Returns immediately with a {@code CompletableFuture<Void>} which
|
||||
* completes normally when the message has been sent, or completes
|
||||
* exceptionally if an error occurs.
|
||||
* <p> Returns a {@code CompletableFuture<WebSocket>} which completes
|
||||
* normally when the message has been sent or completes exceptionally if an
|
||||
* error occurs.
|
||||
*
|
||||
* <p> The returned {@code CompletableFuture} can complete exceptionally
|
||||
* with:
|
||||
* <ul>
|
||||
* <li> {@link IOException}
|
||||
* if an I/O error occurs during this operation or the
|
||||
* {@code WebSocket} closes while this operation is in progress
|
||||
* if an I/O error occurs during this operation
|
||||
* <li> {@link IllegalStateException}
|
||||
* if the {@code WebSocket} closes while this operation is in progress;
|
||||
* or if a Close message has been sent already;
|
||||
* or if there is an outstanding send operation
|
||||
* </ul>
|
||||
*
|
||||
* @return a CompletableFuture of Void
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if the WebSocket is closed
|
||||
* @throws IllegalStateException
|
||||
* if a Close message has been already sent
|
||||
* @throws IllegalStateException
|
||||
* if there is an outstanding send operation
|
||||
* @return a CompletableFuture with this WebSocket
|
||||
*/
|
||||
CompletableFuture<Void> sendClose();
|
||||
CompletableFuture<WebSocket> sendClose();
|
||||
|
||||
/**
|
||||
* Requests {@code n} more messages to be received by the {@link Listener
|
||||
@ -1001,6 +926,7 @@ public interface WebSocket {
|
||||
* @implNote This implementation does not distinguish between partial and
|
||||
* whole messages, because it's not known beforehand how a message will be
|
||||
* received.
|
||||
*
|
||||
* <p> If a server sends more messages than requested, the implementation
|
||||
* queues up these messages on the TCP connection and may eventually force
|
||||
* the sender to stop sending through TCP flow control.
|
||||
@ -1242,47 +1168,4 @@ public interface WebSocket {
|
||||
return Map.entry(cc.getCode(), cc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A character sequence that provides access to the characters UTF-8 decoded
|
||||
* from a message in a {@code ByteBuffer}.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
interface Text extends CharSequence {
|
||||
|
||||
// Methods from the CharSequence below are mentioned explicitly for the
|
||||
// purpose of documentation, so when looking at javadoc it immediately
|
||||
// obvious what methods Text has
|
||||
|
||||
@Override
|
||||
int length();
|
||||
|
||||
@Override
|
||||
char charAt(int index);
|
||||
|
||||
@Override
|
||||
CharSequence subSequence(int start, int end);
|
||||
|
||||
/**
|
||||
* Returns a string containing the characters in this sequence in the
|
||||
* same order as this sequence. The length of the string will be the
|
||||
* length of this sequence.
|
||||
*
|
||||
* @return a string consisting of exactly this sequence of characters
|
||||
*/
|
||||
@Override
|
||||
// TODO: remove the explicit javadoc above when:
|
||||
// (JDK-8144034 has been resolved) AND (the comment is still identical
|
||||
// to CharSequence#toString)
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Returns a read-only {@code ByteBuffer} containing the message encoded
|
||||
* in UTF-8.
|
||||
*
|
||||
* @return a read-only ByteBuffer
|
||||
*/
|
||||
ByteBuffer asByteBuffer();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -128,7 +128,7 @@ public interface ScriptEngineFactory {
|
||||
* of "MULTITHREADED", and also, the engine maintains independent values
|
||||
* for symbols in scripts executing on different threads.
|
||||
* <li><code>"STATELESS"</code> - The implementation satisfies the requirements of
|
||||
* <li><code>"THREAD-ISOLATED"</code>. In addition, script executions do not alter the
|
||||
* <code>"THREAD-ISOLATED"</code>. In addition, script executions do not alter the
|
||||
* mappings in the <code>Bindings</code> which is the engine scope of the
|
||||
* <code>ScriptEngine</code>. In particular, the keys in the <code>Bindings</code>
|
||||
* and their associated values are the same before and after the execution of the script.
|
||||
|
@ -54,7 +54,9 @@ public abstract class EditingHistory implements History {
|
||||
(Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::previousSnippet));
|
||||
bind(in, CTRL_DOWN,
|
||||
(Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::nextSnippet));
|
||||
load(originalHistory);
|
||||
if (originalHistory != null) {
|
||||
load(originalHistory);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveHistoryToSnippet(ConsoleReader in, Supplier<Boolean> action) {
|
||||
|
@ -28,19 +28,16 @@ package jdk.tools.jimage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import static java.nio.file.StandardOpenOption.READ;
|
||||
import static java.nio.file.StandardOpenOption.WRITE;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.function.Predicate;
|
||||
import jdk.internal.jimage.BasicImageReader;
|
||||
import jdk.internal.jimage.ImageHeader;
|
||||
import static jdk.internal.jimage.ImageHeader.MAGIC;
|
||||
import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION;
|
||||
import static jdk.internal.jimage.ImageHeader.MINOR_VERSION;
|
||||
import jdk.internal.jimage.ImageLocation;
|
||||
import jdk.tools.jlink.internal.ImageResourcesTree;
|
||||
import jdk.tools.jlink.internal.TaskHelper;
|
||||
@ -48,53 +45,71 @@ import jdk.tools.jlink.internal.TaskHelper.BadArgs;
|
||||
import static jdk.tools.jlink.internal.TaskHelper.JIMAGE_BUNDLE;
|
||||
import jdk.tools.jlink.internal.TaskHelper.Option;
|
||||
import jdk.tools.jlink.internal.TaskHelper.OptionsHelper;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
class JImageTask {
|
||||
|
||||
static final Option<?>[] recognizedOptions = {
|
||||
new Option<JImageTask>(true, (task, opt, arg) -> {
|
||||
private static final Option<?>[] RECOGNIZED_OPTIONS = {
|
||||
new Option<JImageTask>(true, (task, option, arg) -> {
|
||||
task.options.directory = arg;
|
||||
}, "--dir"),
|
||||
new Option<JImageTask>(false, (task, opt, arg) -> {
|
||||
|
||||
new Option<JImageTask>(true, (task, option, arg) -> {
|
||||
task.options.filters = arg;
|
||||
}, "--filter"),
|
||||
|
||||
new Option<JImageTask>(false, (task, option, arg) -> {
|
||||
task.options.fullVersion = true;
|
||||
}, true, "--fullversion"),
|
||||
new Option<JImageTask>(false, (task, opt, arg) -> {
|
||||
|
||||
new Option<JImageTask>(false, (task, option, arg) -> {
|
||||
task.options.help = true;
|
||||
}, "--help"),
|
||||
new Option<JImageTask>(true, (task, opt, arg) -> {
|
||||
task.options.flags = arg;
|
||||
}, "--flags"),
|
||||
new Option<JImageTask>(false, (task, opt, arg) -> {
|
||||
|
||||
new Option<JImageTask>(false, (task, option, arg) -> {
|
||||
task.options.verbose = true;
|
||||
}, "--verbose"),
|
||||
new Option<JImageTask>(false, (task, opt, arg) -> {
|
||||
|
||||
new Option<JImageTask>(false, (task, option, arg) -> {
|
||||
task.options.version = true;
|
||||
}, "--version")
|
||||
};
|
||||
private static final TaskHelper taskHelper
|
||||
private static final TaskHelper TASK_HELPER
|
||||
= new TaskHelper(JIMAGE_BUNDLE);
|
||||
private static final OptionsHelper<JImageTask> optionsHelper
|
||||
= taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions);
|
||||
private static final OptionsHelper<JImageTask> OPTION_HELPER
|
||||
= TASK_HELPER.newOptionsHelper(JImageTask.class, RECOGNIZED_OPTIONS);
|
||||
private static final String PROGNAME = "jimage";
|
||||
private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
|
||||
|
||||
private final OptionsValues options;
|
||||
private final List<Predicate<String>> filterPredicates;
|
||||
private PrintWriter log;
|
||||
|
||||
JImageTask() {
|
||||
this.options = new OptionsValues();
|
||||
this.filterPredicates = new ArrayList<>();
|
||||
log = null;
|
||||
}
|
||||
|
||||
void setLog(PrintWriter out) {
|
||||
log = out;
|
||||
TASK_HELPER.setLog(log);
|
||||
}
|
||||
|
||||
static class OptionsValues {
|
||||
Task task = Task.LIST;
|
||||
String directory = ".";
|
||||
String filters = "";
|
||||
boolean fullVersion;
|
||||
boolean help;
|
||||
String flags;
|
||||
boolean verbose;
|
||||
boolean version;
|
||||
List<File> jimages = new LinkedList<>();
|
||||
}
|
||||
|
||||
private static final String PROGNAME = "jimage";
|
||||
private final OptionsValues options = new OptionsValues();
|
||||
|
||||
enum Task {
|
||||
EXTRACT,
|
||||
INFO,
|
||||
LIST,
|
||||
SET,
|
||||
VERIFY
|
||||
};
|
||||
|
||||
@ -145,50 +160,97 @@ class JImageTask {
|
||||
|
||||
int run(String[] args) {
|
||||
if (log == null) {
|
||||
setLog(new PrintWriter(System.out));
|
||||
setLog(new PrintWriter(System.out, true));
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
|
||||
log.println(TASK_HELPER.getMessage("main.usage.summary", PROGNAME));
|
||||
return EXIT_ABNORMAL;
|
||||
}
|
||||
|
||||
try {
|
||||
List<String> unhandled = optionsHelper.handleOptions(this, args);
|
||||
List<String> unhandled = OPTION_HELPER.handleOptions(this, args);
|
||||
|
||||
if(!unhandled.isEmpty()) {
|
||||
try {
|
||||
options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw taskHelper.newBadArgs("err.not.a.task", unhandled.get(0));
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
|
||||
}
|
||||
|
||||
for(int i = 1; i < unhandled.size(); i++) {
|
||||
options.jimages.add(new File(unhandled.get(i)));
|
||||
}
|
||||
} else {
|
||||
throw taskHelper.newBadArgs("err.not.a.task", "<unspecified>");
|
||||
} else if (!options.help && !options.version && !options.fullVersion) {
|
||||
throw TASK_HELPER.newBadArgs("err.invalid.task", "<unspecified>");
|
||||
}
|
||||
|
||||
if (options.help) {
|
||||
optionsHelper.showHelp(PROGNAME);
|
||||
if (unhandled.isEmpty()) {
|
||||
log.println(TASK_HELPER.getMessage("main.usage", PROGNAME));
|
||||
|
||||
for (Option<?> o : RECOGNIZED_OPTIONS) {
|
||||
String name = o.aliases()[0];
|
||||
|
||||
if (name.startsWith("--")) {
|
||||
name = name.substring(2);
|
||||
} else if (name.startsWith("-")) {
|
||||
name = name.substring(1);
|
||||
}
|
||||
|
||||
log.println(TASK_HELPER.getMessage("main.opt." + name));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
log.println(TASK_HELPER.getMessage("main.usage." +
|
||||
options.task.toString().toLowerCase()));
|
||||
} catch (MissingResourceException ex) {
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
|
||||
}
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (options.version || options.fullVersion) {
|
||||
taskHelper.showVersion(options.fullVersion);
|
||||
TASK_HELPER.showVersion(options.fullVersion);
|
||||
|
||||
if (unhandled.isEmpty()) {
|
||||
return EXIT_OK;
|
||||
}
|
||||
}
|
||||
boolean ok = run();
|
||||
return ok ? EXIT_OK : EXIT_ERROR;
|
||||
|
||||
processFilter(options.filters);
|
||||
|
||||
return run() ? EXIT_OK : EXIT_ERROR;
|
||||
} catch (BadArgs e) {
|
||||
taskHelper.reportError(e.key, e.args);
|
||||
TASK_HELPER.reportError(e.key, e.args);
|
||||
|
||||
if (e.showUsage) {
|
||||
log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
|
||||
log.println(TASK_HELPER.getMessage("main.usage.summary", PROGNAME));
|
||||
}
|
||||
|
||||
return EXIT_CMDERR;
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace();
|
||||
|
||||
return EXIT_ABNORMAL;
|
||||
} finally {
|
||||
log.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void processFilter(String filters) {
|
||||
if (filters.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String filter : filters.split(",")) {
|
||||
final PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, filter);
|
||||
Predicate<String> predicate = (path) -> matcher.matches(JRT_FILE_SYSTEM.getPath(path));
|
||||
filterPredicates.add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
private void listTitle(File file, BasicImageReader reader) {
|
||||
log.println("jimage: " + file);
|
||||
}
|
||||
@ -216,10 +278,12 @@ class JImageTask {
|
||||
|
||||
if (parent.exists()) {
|
||||
if (!parent.isDirectory()) {
|
||||
throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
|
||||
throw TASK_HELPER.newBadArgs("err.cannot.create.dir",
|
||||
parent.getAbsolutePath());
|
||||
}
|
||||
} else if (!parent.mkdirs()) {
|
||||
throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
|
||||
throw TASK_HELPER.newBadArgs("err.cannot.create.dir",
|
||||
parent.getAbsolutePath());
|
||||
}
|
||||
|
||||
if (!ImageResourcesTree.isTreeInfoResource(name)) {
|
||||
@ -261,7 +325,7 @@ class JImageTask {
|
||||
|
||||
log.println(" Major Version: " + header.getMajorVersion());
|
||||
log.println(" Minor Version: " + header.getMinorVersion());
|
||||
log.println(" Flags: " + Integer.toHexString(header.getMinorVersion()));
|
||||
log.println(" Flags: " + Integer.toHexString(header.getFlags()));
|
||||
log.println(" Resource Count: " + header.getResourceCount());
|
||||
log.println(" Table Length: " + header.getTableLength());
|
||||
log.println(" Offsets Size: " + header.getOffsetsSize());
|
||||
@ -287,36 +351,7 @@ class JImageTask {
|
||||
print(reader, name);
|
||||
}
|
||||
|
||||
void set(File file, BasicImageReader reader) throws BadArgs {
|
||||
try {
|
||||
ImageHeader oldHeader = reader.getHeader();
|
||||
|
||||
int value = 0;
|
||||
try {
|
||||
value = Integer.valueOf(options.flags);
|
||||
} catch (NumberFormatException ex) {
|
||||
throw taskHelper.newBadArgs("err.flags.not.int", options.flags);
|
||||
}
|
||||
|
||||
ImageHeader newHeader = new ImageHeader(MAGIC, MAJOR_VERSION, MINOR_VERSION,
|
||||
value,
|
||||
oldHeader.getResourceCount(), oldHeader.getTableLength(),
|
||||
oldHeader.getLocationsSize(), oldHeader.getStringsSize());
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(ImageHeader.getHeaderSize());
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
newHeader.writeTo(buffer);
|
||||
buffer.rewind();
|
||||
|
||||
try (FileChannel channel = FileChannel.open(file.toPath(), READ, WRITE)) {
|
||||
channel.write(buffer, 0);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw taskHelper.newBadArgs("err.cannot.update.file", file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
void verify(BasicImageReader reader, String name, ImageLocation location) {
|
||||
void verify(BasicImageReader reader, String name, ImageLocation location) {
|
||||
if (name.endsWith(".class")) {
|
||||
byte[] bytes = reader.getResource(location);
|
||||
|
||||
@ -335,12 +370,12 @@ class JImageTask {
|
||||
ModuleAction moduleAction,
|
||||
ResourceAction resourceAction) throws IOException, BadArgs {
|
||||
if (options.jimages.isEmpty()) {
|
||||
throw taskHelper.newBadArgs("err.no.jimage");
|
||||
throw TASK_HELPER.newBadArgs("err.no.jimage");
|
||||
}
|
||||
|
||||
for (File file : options.jimages) {
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
throw taskHelper.newBadArgs("err.not.a.jimage", file.getName());
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.jimage", file.getName());
|
||||
}
|
||||
|
||||
try (BasicImageReader reader = BasicImageReader.open(file.toPath())) {
|
||||
@ -353,6 +388,19 @@ class JImageTask {
|
||||
String oldModule = "";
|
||||
|
||||
for (String name : entryNames) {
|
||||
boolean match = filterPredicates.isEmpty();
|
||||
|
||||
for (Predicate<String> predicate : filterPredicates) {
|
||||
if (predicate.test(name)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ImageResourcesTree.isTreeInfoResource(name)) {
|
||||
if (moduleAction != null) {
|
||||
int offset = name.indexOf('/', 1);
|
||||
@ -387,21 +435,13 @@ class JImageTask {
|
||||
case LIST:
|
||||
iterate(this::listTitle, this::listModule, this::list);
|
||||
break;
|
||||
case SET:
|
||||
iterate(this::set, null, null);
|
||||
break;
|
||||
case VERIFY:
|
||||
iterate(this::listTitle, null, this::verify);
|
||||
break;
|
||||
default:
|
||||
throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true);
|
||||
throw TASK_HELPER.newBadArgs("err.invalid.task",
|
||||
options.task.name()).showUsage(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private PrintWriter log;
|
||||
void setLog(PrintWriter out) {
|
||||
log = out;
|
||||
taskHelper.setLog(log);
|
||||
}
|
||||
}
|
||||
|
@ -24,54 +24,67 @@
|
||||
#
|
||||
|
||||
main.usage.summary=\
|
||||
Usage: {0} <extract|info|list|set|verify> <options> jimage...\n\
|
||||
use --help for a list of possible options
|
||||
Usage: {0} <extract | info | list | verify> <options> jimage...\n\
|
||||
use --help for a list of possible options.
|
||||
|
||||
main.usage=\
|
||||
Usage: {0} <extract|info|list|set|verify> <options> jimage...\n\
|
||||
Usage: {0} <extract | info | list | verify> <options> jimage...\n\
|
||||
\n\
|
||||
\ extract - Extract all jimage entries and place in a directory specified\n\
|
||||
\ by the --dir=<directory> (default='.') option.\n\
|
||||
\n\
|
||||
\ info - Prints detailed information contained in the jimage header.\n\
|
||||
\n\
|
||||
\ extract - Extract all jimage entries into separate files into the directory\n\
|
||||
\ specified by --dir=<directory> (default='.')\n\
|
||||
\ info - Prints information specified in the jimage header.\n\
|
||||
\ list - Prints the names of all the entries in the jimage. When used with\n\
|
||||
\ --verbose will also print entry attributes ex. size and offset.\n\
|
||||
\ set - sets the value of specific jimage header entries\n\
|
||||
\ verify - Reports errors on any .class entries that don't verify as classes.\n\
|
||||
\ --verbose, list will also print entry size and offset attributes.\n\
|
||||
\n\
|
||||
\ verify - Reports on any .class entries that don't verify as classes.\n\
|
||||
\n\
|
||||
Possible options include:
|
||||
|
||||
main.usage.extract=\
|
||||
\ extract - Extract all jimage entries and place in a directory specified\n\
|
||||
\ by the --dir=<directory> (default='.') option.
|
||||
|
||||
main.usage.info=\
|
||||
\ info - Prints detailed information contained in the jimage header.
|
||||
|
||||
main.usage.list=\
|
||||
\ list - Prints the names of all the entries in the jimage. When used with\n\
|
||||
\ --verbose, list will also print entry size and offset attributes.
|
||||
|
||||
main.usage.verify=\
|
||||
\ verify - Reports errors on any .class entries that don't verify as classes.
|
||||
|
||||
error.prefix=Error:
|
||||
warn.prefix=Warning:
|
||||
|
||||
main.opt.dir=\
|
||||
\ --dir Target directory for extract
|
||||
\ --dir Target directory for extract directive
|
||||
|
||||
main.opt.flags=\
|
||||
\ --flags=value Set the jimage flags to value
|
||||
main.opt.filter=\
|
||||
\ --filter Filter entries for list or extract\n\
|
||||
\ Ex. /java.base/*, */module-info.class
|
||||
|
||||
main.opt.fullversion=\
|
||||
\ --fullversion Print full version information
|
||||
|
||||
main.opt.help=\
|
||||
\ --help Print this usage message
|
||||
\ --help Print usage message
|
||||
|
||||
main.opt.verbose=\
|
||||
\ --verbose Verbose listing
|
||||
\ --verbose Listing prints entry size and offset attributes
|
||||
|
||||
main.opt.version=\
|
||||
\ --version Version information
|
||||
\ --version Print version information
|
||||
|
||||
main.command.files=\
|
||||
\ @<filename> Read options from file
|
||||
err.cannot.read.file=cannot read file: {0}
|
||||
err.cannot.update.file=cannot update file: {0}
|
||||
err.file.not.found=cannot find file: {0}
|
||||
err.file.error=cannot access file: {0}
|
||||
err.flags.not.int=--flags value not integer: {0}
|
||||
err.internal.error=internal error: {0} {1} {2}
|
||||
err.invalid.arg.for.option=invalid argument for option: {0}
|
||||
err.invalid.task=task must be extract|info|list|verify: {0}
|
||||
\ @<filename> Read options from file
|
||||
|
||||
err.not.a.task=task must be one of <extract | info | list | verify>: {0}
|
||||
err.missing.arg=no value given for {0}
|
||||
err.not.a.dir=not a directory: {0}
|
||||
err.not.a.jimage=not a jimage file: {0}
|
||||
err.no.jimage=no jimage provided
|
||||
err.not.a.task=not a valid task: {0}
|
||||
err.option.unsupported={0} not supported: {1}
|
||||
err.unknown.option=unknown option: {0}
|
||||
|
@ -186,7 +186,7 @@ public class JlinkTask {
|
||||
|
||||
int run(String[] args) {
|
||||
if (log == null) {
|
||||
setLog(new PrintWriter(System.err));
|
||||
setLog(new PrintWriter(System.err, true));
|
||||
}
|
||||
try {
|
||||
optionsHelper.handleOptions(this, args);
|
||||
|
@ -136,6 +136,10 @@ public final class TaskHelper {
|
||||
void process(T task, String opt, String arg) throws BadArgs {
|
||||
processing.process(task, opt, arg);
|
||||
}
|
||||
|
||||
public String[] aliases() {
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PlugOption extends Option<PluginsOptions> {
|
||||
|
@ -25,6 +25,10 @@
|
||||
package jdk.tools.jlink.internal;
|
||||
|
||||
import java.lang.reflect.Module;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
@ -155,4 +159,20 @@ public class Utils {
|
||||
public static boolean isBuiltin(Plugin prov) {
|
||||
return THIS_MODULE.equals(prov.getClass().getModule());
|
||||
}
|
||||
|
||||
public static FileSystem jrtFileSystem() {
|
||||
return FileSystems.getFileSystem(URI.create("jrt:/"));
|
||||
}
|
||||
|
||||
public static PathMatcher getPathMatcher(FileSystem fs, String pattern) {
|
||||
if (!pattern.startsWith("glob:") && !pattern.startsWith("regex:")) {
|
||||
pattern = "glob:" + pattern;
|
||||
}
|
||||
|
||||
return fs.getPathMatcher(pattern);
|
||||
}
|
||||
|
||||
public static PathMatcher getPathMatcher(String pattern) {
|
||||
return getPathMatcher(jrtFileSystem(), pattern);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,9 @@ package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -47,6 +49,8 @@ import jdk.tools.jlink.internal.Utils;
|
||||
*/
|
||||
public final class OrderResourcesPlugin implements TransformerPlugin {
|
||||
public static final String NAME = "order-resources";
|
||||
private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
|
||||
|
||||
private final List<ToIntFunction<String>> filters;
|
||||
private final Map<String, Integer> orderedPaths;
|
||||
|
||||
@ -187,27 +191,11 @@ public final class OrderResourcesPlugin implements TransformerPlugin {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean endsWith = pattern.startsWith("*");
|
||||
boolean startsWith = pattern.endsWith("*");
|
||||
ToIntFunction<String> function;
|
||||
final int result = ordinal++;
|
||||
|
||||
if (startsWith && endsWith) {
|
||||
final String string = pattern.substring(1, pattern.length() - 1);
|
||||
function = (path)-> path.contains(string) ? result : Integer.MAX_VALUE;
|
||||
} else if (startsWith) {
|
||||
final String string = pattern.substring(0, pattern.length() - 1);
|
||||
function = (path)-> path.startsWith(string) ? result : Integer.MAX_VALUE;
|
||||
} else if (endsWith) {
|
||||
final String string = pattern.substring(1);
|
||||
function = (path)-> path.endsWith(string) ? result : Integer.MAX_VALUE;
|
||||
} else {
|
||||
final String string = pattern;
|
||||
function = (path)-> path.equals(string) ? result : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
final PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, pattern);
|
||||
ToIntFunction<String> function = (path)-> matcher.matches(JRT_FILE_SYSTEM.getPath(path)) ? result : Integer.MAX_VALUE;
|
||||
filters.add(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,113 +24,71 @@
|
||||
*/
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Filter in or out a resource
|
||||
* Filter resource resources using path matcher.
|
||||
*/
|
||||
public class ResourceFilter implements Predicate<String> {
|
||||
private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
|
||||
|
||||
private final Pattern inPatterns;
|
||||
private final Pattern outPatterns;
|
||||
|
||||
static final String NEG = "^";
|
||||
final boolean negate;
|
||||
final List<PathMatcher> matchers;
|
||||
|
||||
public ResourceFilter(String[] patterns) throws IOException {
|
||||
this(patterns, false);
|
||||
}
|
||||
|
||||
public ResourceFilter(String[] patterns, boolean negateAll) throws IOException {
|
||||
public ResourceFilter(String[] patterns, boolean negate) throws IOException {
|
||||
this.negate = negate;
|
||||
this.matchers = new ArrayList<>();
|
||||
|
||||
// Get the patterns from a file
|
||||
if (patterns != null && patterns.length == 1) {
|
||||
String filePath = patterns[0];
|
||||
File f = new File(filePath);
|
||||
if (f.exists()) {
|
||||
List<String> pats;
|
||||
try (FileInputStream fis = new FileInputStream(f);
|
||||
InputStreamReader ins = new InputStreamReader(fis,
|
||||
StandardCharsets.UTF_8);
|
||||
BufferedReader reader = new BufferedReader(ins)) {
|
||||
pats = reader.lines().collect(Collectors.toList());
|
||||
for (String pattern : patterns) {
|
||||
if (pattern.startsWith("@")) {
|
||||
File file = new File(pattern.substring(1));
|
||||
|
||||
if (file.exists()) {
|
||||
List<String> lines;
|
||||
|
||||
try {
|
||||
lines = Files.readAllLines(file.toPath());
|
||||
} catch (IOException ex) {
|
||||
throw new PluginException(ex);
|
||||
}
|
||||
|
||||
for (String line : lines) {
|
||||
PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, line);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
}
|
||||
patterns = new String[pats.size()];
|
||||
pats.toArray(patterns);
|
||||
} else {
|
||||
PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, pattern);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
if (patterns != null && negateAll) {
|
||||
String[] excluded = new String[patterns.length];
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
excluded[i] = ResourceFilter.NEG + patterns[i];
|
||||
}
|
||||
patterns = excluded;
|
||||
}
|
||||
|
||||
StringBuilder inPatternsBuilder = new StringBuilder();
|
||||
StringBuilder outPatternsBuilder = new StringBuilder();
|
||||
if (patterns != null) {
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
String p = patterns[i];
|
||||
p = p.replaceAll(" ", "");
|
||||
StringBuilder builder = p.startsWith(NEG)
|
||||
? outPatternsBuilder : inPatternsBuilder;
|
||||
String pat = p.startsWith(NEG) ? p.substring(NEG.length()) : p;
|
||||
builder.append(escape(pat));
|
||||
if (i < patterns.length - 1) {
|
||||
builder.append("|");
|
||||
}
|
||||
}
|
||||
}
|
||||
this.inPatterns = inPatternsBuilder.length() == 0 ? null
|
||||
: Pattern.compile(inPatternsBuilder.toString());
|
||||
this.outPatterns = outPatternsBuilder.length() == 0 ? null
|
||||
: Pattern.compile(outPatternsBuilder.toString());
|
||||
}
|
||||
|
||||
public static String escape(String s) {
|
||||
s = s.replaceAll(" ", "");
|
||||
s = s.replaceAll("\\$", Matcher.quoteReplacement("\\$"));
|
||||
s = s.replaceAll("\\.", Matcher.quoteReplacement("\\."));
|
||||
s = s.replaceAll("\\*", ".+");
|
||||
return s;
|
||||
}
|
||||
|
||||
private boolean accept(String path) {
|
||||
if (outPatterns != null) {
|
||||
Matcher mout = outPatterns.matcher(path);
|
||||
if (mout.matches()) {
|
||||
//System.out.println("Excluding file " + resource.getPath());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean accepted = false;
|
||||
// If the inPatterns is null, means that all resources are accepted.
|
||||
if (inPatterns == null) {
|
||||
accepted = true;
|
||||
} else {
|
||||
Matcher m = inPatterns.matcher(path);
|
||||
if (m.matches()) {
|
||||
//System.out.println("Including file " + resource.getPath());
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(String path) {
|
||||
return accept(path);
|
||||
public boolean test(String name) {
|
||||
Path path = JRT_FILE_SYSTEM.getPath(name);
|
||||
|
||||
for (PathMatcher matcher : matchers) {
|
||||
if (matcher.matches(path)) {
|
||||
return !negate;
|
||||
}
|
||||
}
|
||||
|
||||
return negate;
|
||||
}
|
||||
}
|
||||
|
@ -1072,6 +1072,10 @@ public class JmodTask {
|
||||
@Override
|
||||
public Pattern convert(String value) {
|
||||
try {
|
||||
if (value.startsWith("regex:")) {
|
||||
value = value.substring("regex:".length()).trim();
|
||||
}
|
||||
|
||||
return Pattern.compile(value);
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new CommandException("err.bad.pattern", value);
|
||||
@ -1083,10 +1087,15 @@ public class JmodTask {
|
||||
@Override public String valuePattern() { return "pattern"; }
|
||||
}
|
||||
|
||||
static class GlobConverter implements ValueConverter<PathMatcher> {
|
||||
static class PathMatcherConverter implements ValueConverter<PathMatcher> {
|
||||
@Override
|
||||
public PathMatcher convert(String pattern) {
|
||||
try {
|
||||
if (!pattern.startsWith("glob:") &&
|
||||
!pattern.startsWith("regex:")) {
|
||||
pattern = "glob:" + pattern;
|
||||
}
|
||||
|
||||
return FileSystems.getDefault()
|
||||
.getPathMatcher("glob:" + pattern);
|
||||
} catch (PatternSyntaxException e) {
|
||||
@ -1194,7 +1203,7 @@ public class JmodTask {
|
||||
OptionSpec<PathMatcher> excludes
|
||||
= parser.accepts("exclude", getMessage("main.opt.exclude"))
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(new GlobConverter());
|
||||
.withValuesConvertedBy(new PathMatcherConverter());
|
||||
|
||||
OptionSpec<Pattern> hashModules
|
||||
= parser.accepts("hash-modules", getMessage("main.opt.hash-modules"))
|
||||
|
@ -167,6 +167,8 @@ java/net/MulticastSocket/Test.java 7145658 macosx-a
|
||||
|
||||
java/net/DatagramSocket/SendDatagramToBadAddress.java 7143960 macosx-all
|
||||
|
||||
sun/net/www/http/ChunkedOutputStream/checkError.java 8041924 linux-all
|
||||
|
||||
############################################################################
|
||||
|
||||
# jdk_nio
|
||||
@ -199,6 +201,8 @@ java/rmi/activation/Activatable/extLoadedImpl/ext.sh 8062724 generic-
|
||||
|
||||
sun/rmi/rmic/newrmic/equivalence/run.sh 8145980 generic-all
|
||||
|
||||
java/rmi/transport/dgcDeadLock/DGCDeadLock.java 8029360 macosx-all
|
||||
|
||||
############################################################################
|
||||
|
||||
# jdk_security
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -150,11 +150,6 @@ public abstract class TestCipher {
|
||||
}
|
||||
|
||||
// Encryption
|
||||
int PAD_LEN = 0;
|
||||
if (pad.equalsIgnoreCase("PKCS5Padding")) {
|
||||
// Need to consider pad bytes
|
||||
PAD_LEN = 8;
|
||||
}
|
||||
|
||||
byte[] plainText = INPUT_TEXT.clone();
|
||||
|
||||
@ -162,12 +157,13 @@ public abstract class TestCipher {
|
||||
byte[] cipherText = ci.doFinal(INPUT_TEXT, ENC_OFFSET, TEXT_LEN);
|
||||
|
||||
// Generate cipher and save to same buffer
|
||||
int offset = ci.update(
|
||||
int enc_bytes = ci.update(
|
||||
INPUT_TEXT, ENC_OFFSET, TEXT_LEN, INPUT_TEXT, STORAGE_OFFSET);
|
||||
ci.doFinal(INPUT_TEXT, offset + STORAGE_OFFSET);
|
||||
enc_bytes += ci.doFinal(INPUT_TEXT, enc_bytes + STORAGE_OFFSET);
|
||||
|
||||
if (!equalsBlock(
|
||||
INPUT_TEXT, STORAGE_OFFSET, cipherText, 0, cipherText.length)) {
|
||||
INPUT_TEXT, STORAGE_OFFSET, enc_bytes,
|
||||
cipherText, 0, cipherText.length)) {
|
||||
throw new RuntimeException(
|
||||
"Different ciphers generated with same buffer");
|
||||
}
|
||||
@ -183,8 +179,8 @@ public abstract class TestCipher {
|
||||
byte[] recoveredText = ci.doFinal(cipherText, 0, cipherText.length);
|
||||
|
||||
if (!equalsBlock(
|
||||
plainText, ENC_OFFSET, recoveredText, 0,
|
||||
recoveredText.length)) {
|
||||
plainText, ENC_OFFSET, TEXT_LEN,
|
||||
recoveredText, 0, recoveredText.length)) {
|
||||
throw new RuntimeException(
|
||||
"Recovered text not same as plain text");
|
||||
} else {
|
||||
@ -192,13 +188,13 @@ public abstract class TestCipher {
|
||||
}
|
||||
|
||||
// Recover text from cipher and save to same buffer
|
||||
ci.update(INPUT_TEXT, STORAGE_OFFSET, TEXT_LEN + PAD_LEN, INPUT_TEXT,
|
||||
ENC_OFFSET);
|
||||
ci.doFinal(INPUT_TEXT, ENC_OFFSET);
|
||||
int dec_bytes = ci.update(
|
||||
INPUT_TEXT, STORAGE_OFFSET, enc_bytes, INPUT_TEXT, ENC_OFFSET);
|
||||
dec_bytes += ci.doFinal(INPUT_TEXT, dec_bytes + ENC_OFFSET);
|
||||
|
||||
if (!equalsBlock(
|
||||
plainText, ENC_OFFSET, recoveredText, 0,
|
||||
recoveredText.length)) {
|
||||
plainText, ENC_OFFSET, TEXT_LEN,
|
||||
INPUT_TEXT, ENC_OFFSET, dec_bytes)) {
|
||||
throw new RuntimeException(
|
||||
"Recovered text not same as plain text with same buffer");
|
||||
} else {
|
||||
@ -208,9 +204,12 @@ public abstract class TestCipher {
|
||||
out.println("Test Passed.");
|
||||
}
|
||||
|
||||
private static boolean equalsBlock(byte[] b1, int off1, byte[] b2, int off2,
|
||||
int len) {
|
||||
for (int i = off1, j = off2, k = 0; k < len; i++, j++, k++) {
|
||||
private static boolean equalsBlock(byte[] b1, int off1, int len1,
|
||||
byte[] b2, int off2, int len2) {
|
||||
if (len1 != len2) {
|
||||
return false;
|
||||
}
|
||||
for (int i = off1, j = off2, k = 0; k < len1; i++, j++, k++) {
|
||||
if (b1[i] != b2[j]) {
|
||||
return false;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import java.security.Permission;
|
||||
/**
|
||||
* @test
|
||||
* @summary String concatenation fails with a custom SecurityManager that uses concatenation
|
||||
* @bug 8155090
|
||||
* @bug 8155090 8158851
|
||||
*
|
||||
* @compile WithSecurityManager.java
|
||||
*
|
||||
@ -37,17 +37,43 @@ import java.security.Permission;
|
||||
* @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT WithSecurityManager
|
||||
*
|
||||
* @run main/othervm -Xverify:all -limitmods java.base WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -limitmods java.base -Djava.lang.invoke.stringConcat=BC_SB WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -limitmods java.base -Djava.lang.invoke.stringConcat=BC_SB_SIZED WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -limitmods java.base -Djava.lang.invoke.stringConcat=MH_SB_SIZED WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -limitmods java.base -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -limitmods java.base -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT WithSecurityManager
|
||||
* @run main/othervm -Xverify:all -limitmods java.base -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT WithSecurityManager
|
||||
*/
|
||||
public class WithSecurityManager {
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SecurityManager sm = new SecurityManager() {
|
||||
@Override
|
||||
public void checkPermission(Permission perm) {
|
||||
String abc = "abc";
|
||||
String full = abc + "def";
|
||||
}
|
||||
};
|
||||
System.setSecurityManager(sm);
|
||||
ClassLoader cl = new ClassLoader() {};
|
||||
// First time should succeed to bootstrap everything
|
||||
{
|
||||
SecurityManager sm = new SecurityManager() {
|
||||
@Override
|
||||
public void checkPermission(Permission perm) {
|
||||
String abc = "abc";
|
||||
String full = abc + "def";
|
||||
}
|
||||
};
|
||||
System.setSecurityManager(sm);
|
||||
ClassLoader cl = new ClassLoader() {
|
||||
};
|
||||
}
|
||||
|
||||
// Second time should succeed to run after bootstrapping
|
||||
{
|
||||
SecurityManager sm = new SecurityManager() {
|
||||
@Override
|
||||
public void checkPermission(Permission perm) {
|
||||
String abc = "abc";
|
||||
String full = abc + "def";
|
||||
}
|
||||
};
|
||||
System.setSecurityManager(sm);
|
||||
ClassLoader cl = new ClassLoader() {
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
77
jdk/test/java/lang/annotation/AnnotationWithLambda.java
Normal file
77
jdk/test/java/lang/annotation/AnnotationWithLambda.java
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8147585
|
||||
* @summary Check Annotation with Lambda, with or without parameter
|
||||
* @run testng AnnotationWithLambda
|
||||
*/
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class AnnotationWithLambda {
|
||||
|
||||
@Test
|
||||
void testAnnotationWithLambda() {
|
||||
Method[] methods = AnnotationWithLambda.MethodsWithAnnotations.class.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
assertTrue((method.isAnnotationPresent(LambdaWithParameter.class)) &&
|
||||
(method.isAnnotationPresent(LambdaWithoutParameter.class)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class MethodsWithAnnotations {
|
||||
|
||||
@LambdaWithParameter
|
||||
@LambdaWithoutParameter
|
||||
public void testAnnotationLambda() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Target(value = ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface LambdaWithParameter {
|
||||
Consumer<Integer> f1 = a -> {
|
||||
System.out.println("lambda has parameter");
|
||||
};
|
||||
}
|
||||
|
||||
@Target(value = ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface LambdaWithoutParameter {
|
||||
Runnable r = () -> System.out.println("lambda without parameter");
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.net.http.HttpClient;
|
||||
import java.net.http.WebSocket;
|
||||
import java.net.http.WebSocket.CloseCode;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -90,12 +91,24 @@ public class BasicWebSocketAPITest {
|
||||
"message",
|
||||
() -> ws.sendBinary((ByteBuffer) null, true))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
TestKit.assertThrows(IllegalArgumentException.class,
|
||||
".*message.*",
|
||||
() -> ws.sendPing(ByteBuffer.allocate(126)))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
TestKit.assertThrows(NullPointerException.class,
|
||||
"message",
|
||||
() -> ws.sendPing(null))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
TestKit.assertThrows(IllegalArgumentException.class,
|
||||
".*message.*",
|
||||
() -> ws.sendPong(ByteBuffer.allocate(126)))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
TestKit.assertThrows(NullPointerException.class,
|
||||
@ -106,7 +119,7 @@ public class BasicWebSocketAPITest {
|
||||
(ws) ->
|
||||
TestKit.assertThrows(NullPointerException.class,
|
||||
"message",
|
||||
() -> ws.sendText((CharSequence) null, true))
|
||||
() -> ws.sendText(null, true))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
@ -120,6 +133,12 @@ public class BasicWebSocketAPITest {
|
||||
"message",
|
||||
() -> ws.sendText((Stream<? extends CharSequence>) null))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
TestKit.assertThrows(IllegalArgumentException.class,
|
||||
"(?i).*reason.*",
|
||||
() -> ws.sendClose(CloseCode.NORMAL_CLOSURE, CharBuffer.allocate(124)))
|
||||
);
|
||||
checkAndClose(
|
||||
(ws) ->
|
||||
TestKit.assertThrows(NullPointerException.class,
|
||||
|
494
jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java
Normal file
494
jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8051498 8145849 8158978
|
||||
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
|
||||
* @compile MyX509ExtendedKeyManager.java
|
||||
* @run main/othervm SSLServerSocketAlpnTest h2 h2 h2
|
||||
* @run main/othervm SSLServerSocketAlpnTest h2 h2,http/1.1 h2
|
||||
* @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
|
||||
* @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
|
||||
* @run main/othervm SSLServerSocketAlpnTest h4,h3,h2 h1,h2 h2
|
||||
* @run main/othervm SSLServerSocketAlpnTest EMPTY h2,http/1.1 NONE
|
||||
* @run main/othervm SSLServerSocketAlpnTest h2 EMPTY NONE
|
||||
* @run main/othervm SSLServerSocketAlpnTest H2 h2 ERROR
|
||||
* @run main/othervm SSLServerSocketAlpnTest h2 http/1.1 ERROR
|
||||
* @author Brad Wetmore
|
||||
*/
|
||||
import java.io.*;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
|
||||
public class SSLServerSocketAlpnTest {
|
||||
|
||||
/*
|
||||
* =============================================================
|
||||
* Set the various variables needed for the tests, then
|
||||
* specify what tests to run on each side.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Should we run the client or server in a separate thread?
|
||||
* Both sides can throw exceptions, but do you have a preference
|
||||
* as to which side should be the main thread.
|
||||
*/
|
||||
static boolean separateServerThread = false;
|
||||
|
||||
/*
|
||||
* Where do we find the keystores?
|
||||
*/
|
||||
static String pathToStores = "../etc";
|
||||
static String keyStoreFile = "keystore";
|
||||
static String trustStoreFile = "truststore";
|
||||
static String passwd = "passphrase";
|
||||
|
||||
static String keyFilename = System.getProperty("test.src", ".") + "/"
|
||||
+ pathToStores + "/" + keyStoreFile;
|
||||
static String trustFilename = System.getProperty("test.src", ".") + "/"
|
||||
+ pathToStores + "/" + trustStoreFile;
|
||||
|
||||
/*
|
||||
* SSLContext
|
||||
*/
|
||||
SSLContext mySSLContext = null;
|
||||
|
||||
/*
|
||||
* Is the server ready to serve?
|
||||
*/
|
||||
volatile static boolean serverReady = false;
|
||||
|
||||
/*
|
||||
* Turn on SSL debugging?
|
||||
*/
|
||||
static boolean debug = false;
|
||||
|
||||
static String[] serverAPs;
|
||||
static String[] clientAPs;
|
||||
static String expectedAP;
|
||||
|
||||
/*
|
||||
* If the client or server is doing some kind of object creation
|
||||
* that the other side depends on, and that thread prematurely
|
||||
* exits, you may experience a hang. The test harness will
|
||||
* terminate all hung threads after its timeout has expired,
|
||||
* currently 3 minutes by default, but you might try to be
|
||||
* smart about it....
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define the server side of the test.
|
||||
*
|
||||
* If the server prematurely exits, serverReady will be set to true
|
||||
* to avoid infinite hangs.
|
||||
*/
|
||||
void doServerSide() throws Exception {
|
||||
SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory();
|
||||
SSLServerSocket sslServerSocket
|
||||
= (SSLServerSocket) sslssf.createServerSocket(serverPort);
|
||||
sslServerSocket.setNeedClientAuth(true);
|
||||
|
||||
SSLParameters sslp = sslServerSocket.getSSLParameters();
|
||||
|
||||
// for both client/server to call into X509KM
|
||||
sslp.setNeedClientAuth(true);
|
||||
|
||||
/*
|
||||
* The default ciphersuite ordering from the SSLContext may not
|
||||
* reflect "h2" ciphersuites as being preferred, additionally the
|
||||
* client may not send them in an appropriate order. We could resort
|
||||
* the suite list if so desired.
|
||||
*/
|
||||
String[] suites = sslp.getCipherSuites();
|
||||
sslp.setCipherSuites(suites);
|
||||
sslp.setUseCipherSuitesOrder(true); // Set server side order
|
||||
|
||||
// Set the ALPN selection.
|
||||
sslp.setApplicationProtocols(serverAPs);
|
||||
sslServerSocket.setSSLParameters(sslp);
|
||||
|
||||
serverPort = sslServerSocket.getLocalPort();
|
||||
|
||||
/*
|
||||
* Signal Client, we're ready for his connect.
|
||||
*/
|
||||
serverReady = true;
|
||||
|
||||
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
|
||||
|
||||
if (sslSocket.getHandshakeApplicationProtocol() != null) {
|
||||
throw new Exception ("getHandshakeApplicationProtocol() should "
|
||||
+ "return null before the handshake starts");
|
||||
}
|
||||
|
||||
sslSocket.startHandshake();
|
||||
|
||||
if (sslSocket.getHandshakeApplicationProtocol() != null) {
|
||||
throw new Exception ("getHandshakeApplicationProtocol() should "
|
||||
+ "return null after the handshake is completed");
|
||||
}
|
||||
|
||||
String ap = sslSocket.getApplicationProtocol();
|
||||
System.out.println("Application Protocol: \"" + ap + "\"");
|
||||
|
||||
if (ap == null) {
|
||||
throw new Exception(
|
||||
"Handshake was completed but null was received");
|
||||
}
|
||||
if (expectedAP.equals("NONE")) {
|
||||
if (!ap.isEmpty()) {
|
||||
throw new Exception("Expected no ALPN value");
|
||||
} else {
|
||||
System.out.println("No ALPN value negotiated, as expected");
|
||||
}
|
||||
} else if (!expectedAP.equals(ap)) {
|
||||
throw new Exception(expectedAP
|
||||
+ " ALPN value not available on negotiated connection");
|
||||
}
|
||||
|
||||
InputStream sslIS = sslSocket.getInputStream();
|
||||
OutputStream sslOS = sslSocket.getOutputStream();
|
||||
|
||||
sslIS.read();
|
||||
sslOS.write(85);
|
||||
sslOS.flush();
|
||||
|
||||
sslSocket.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the client side of the test.
|
||||
*
|
||||
* If the server prematurely exits, serverReady will be set to true
|
||||
* to avoid infinite hangs.
|
||||
*/
|
||||
void doClientSide() throws Exception {
|
||||
|
||||
/*
|
||||
* Wait for server to get started.
|
||||
*/
|
||||
while (!serverReady) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
|
||||
SSLSocketFactory sslsf = mySSLContext.getSocketFactory();
|
||||
SSLSocket sslSocket
|
||||
= (SSLSocket) sslsf.createSocket("localhost", serverPort);
|
||||
|
||||
SSLParameters sslp = sslSocket.getSSLParameters();
|
||||
|
||||
/*
|
||||
* The default ciphersuite ordering from the SSLContext may not
|
||||
* reflect "h2" ciphersuites as being preferred, additionally the
|
||||
* client may not send them in an appropriate order. We could resort
|
||||
* the suite list if so desired.
|
||||
*/
|
||||
String[] suites = sslp.getCipherSuites();
|
||||
sslp.setCipherSuites(suites);
|
||||
sslp.setUseCipherSuitesOrder(true); // Set server side order
|
||||
|
||||
// Set the ALPN selection.
|
||||
sslp.setApplicationProtocols(clientAPs);
|
||||
sslSocket.setSSLParameters(sslp);
|
||||
|
||||
if (sslSocket.getHandshakeApplicationProtocol() != null) {
|
||||
throw new Exception ("getHandshakeApplicationProtocol() should "
|
||||
+ "return null before the handshake starts");
|
||||
}
|
||||
|
||||
sslSocket.startHandshake();
|
||||
|
||||
if (sslSocket.getHandshakeApplicationProtocol() != null) {
|
||||
throw new Exception ("getHandshakeApplicationProtocol() should "
|
||||
+ "return null after the handshake is completed");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the resulting connection meets our defined ALPN
|
||||
* criteria. If we were connecting to a non-JSSE implementation,
|
||||
* the server might have negotiated something we shouldn't accept.
|
||||
*/
|
||||
String ap = sslSocket.getApplicationProtocol();
|
||||
System.out.println("Application Protocol: \"" + ap + "\"");
|
||||
|
||||
if (ap == null) {
|
||||
throw new Exception(
|
||||
"Handshake was completed but null was received");
|
||||
}
|
||||
if (expectedAP.equals("NONE")) {
|
||||
if (!ap.isEmpty()) {
|
||||
throw new Exception("Expected no ALPN value");
|
||||
} else {
|
||||
System.out.println("No ALPN value negotiated, as expected");
|
||||
}
|
||||
} else if (!expectedAP.equals(ap)) {
|
||||
throw new Exception(expectedAP
|
||||
+ " ALPN value not available on negotiated connection");
|
||||
}
|
||||
|
||||
InputStream sslIS = sslSocket.getInputStream();
|
||||
OutputStream sslOS = sslSocket.getOutputStream();
|
||||
|
||||
sslOS.write(280);
|
||||
sslOS.flush();
|
||||
sslIS.read();
|
||||
|
||||
sslSocket.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* =============================================================
|
||||
* The remainder is just support stuff
|
||||
*/
|
||||
// use any free port by default
|
||||
volatile int serverPort = 0;
|
||||
|
||||
volatile Exception serverException = null;
|
||||
volatile Exception clientException = null;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (debug) {
|
||||
System.setProperty("javax.net.debug", "all");
|
||||
}
|
||||
|
||||
// Validate parameters
|
||||
if (args.length != 3) {
|
||||
throw new Exception("Invalid number of test parameters");
|
||||
}
|
||||
serverAPs = convert(args[0]);
|
||||
clientAPs = convert(args[1]);
|
||||
expectedAP = args[2];
|
||||
|
||||
/*
|
||||
* Start the tests.
|
||||
*/
|
||||
try {
|
||||
new SSLServerSocketAlpnTest();
|
||||
} catch (SSLHandshakeException she) {
|
||||
if (args[2].equals("ERROR")) {
|
||||
System.out.println("Caught the expected exception: " + she);
|
||||
} else {
|
||||
throw she;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Test Passed.");
|
||||
}
|
||||
|
||||
SSLContext getSSLContext(String keyFilename, String trustFilename)
|
||||
throws Exception {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
|
||||
// Keystores
|
||||
KeyStore keyKS = KeyStore.getInstance("JKS");
|
||||
keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray());
|
||||
|
||||
KeyStore trustKS = KeyStore.getInstance("JKS");
|
||||
trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray());
|
||||
|
||||
// Generate KeyManager and TrustManager
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(keyKS, passwd.toCharArray());
|
||||
|
||||
KeyManager[] kms = kmf.getKeyManagers();
|
||||
if (!(kms[0] instanceof X509ExtendedKeyManager)) {
|
||||
throw new Exception("kms[0] not X509ExtendedKeyManager");
|
||||
}
|
||||
|
||||
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
|
||||
(X509ExtendedKeyManager) kms[0], expectedAP) };
|
||||
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
||||
tmf.init(trustKS);
|
||||
TrustManager[] tms = tmf.getTrustManagers();
|
||||
|
||||
// initial SSLContext
|
||||
ctx.init(kms, tms, null);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a comma-separated list into an array of strings.
|
||||
*/
|
||||
private static String[] convert(String list) {
|
||||
String[] strings;
|
||||
|
||||
if (list.equals("EMPTY")) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
if (list.indexOf(',') > 0) {
|
||||
strings = list.split(",");
|
||||
} else {
|
||||
strings = new String[]{ list };
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
Thread clientThread = null;
|
||||
Thread serverThread = null;
|
||||
|
||||
/*
|
||||
* Primary constructor, used to drive remainder of the test.
|
||||
*
|
||||
* Fork off the other side, then do your work.
|
||||
*/
|
||||
SSLServerSocketAlpnTest() throws Exception {
|
||||
Exception startException = null;
|
||||
mySSLContext = getSSLContext(keyFilename, trustFilename);
|
||||
try {
|
||||
if (separateServerThread) {
|
||||
startServer(true);
|
||||
startClient(false);
|
||||
} else {
|
||||
startClient(true);
|
||||
startServer(false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
startException = e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for other side to close down.
|
||||
*/
|
||||
if (separateServerThread) {
|
||||
if (serverThread != null) {
|
||||
serverThread.join();
|
||||
}
|
||||
} else {
|
||||
if (clientThread != null) {
|
||||
clientThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get here, the test is pretty much over.
|
||||
* Which side threw the error?
|
||||
*/
|
||||
Exception local;
|
||||
Exception remote;
|
||||
|
||||
if (separateServerThread) {
|
||||
remote = serverException;
|
||||
local = clientException;
|
||||
} else {
|
||||
remote = clientException;
|
||||
local = serverException;
|
||||
}
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
/*
|
||||
* Check various exception conditions.
|
||||
*/
|
||||
if ((local != null) && (remote != null)) {
|
||||
// If both failed, return the curthread's exception.
|
||||
local.initCause(remote);
|
||||
exception = local;
|
||||
} else if (local != null) {
|
||||
exception = local;
|
||||
} else if (remote != null) {
|
||||
exception = remote;
|
||||
} else if (startException != null) {
|
||||
exception = startException;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was an exception *AND* a startException,
|
||||
* output it.
|
||||
*/
|
||||
if (exception != null) {
|
||||
if (exception != startException && startException != null) {
|
||||
exception.addSuppressed(startException);
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// Fall-through: no exception to throw!
|
||||
}
|
||||
|
||||
void startServer(boolean newThread) throws Exception {
|
||||
if (newThread) {
|
||||
serverThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Our server thread just died.
|
||||
*
|
||||
* Release the client, if not active already...
|
||||
*/
|
||||
System.err.println("Server died...");
|
||||
serverReady = true;
|
||||
serverException = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
serverThread.start();
|
||||
} else {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
} finally {
|
||||
serverReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startClient(boolean newThread) throws Exception {
|
||||
if (newThread) {
|
||||
clientThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Our client thread just died.
|
||||
*/
|
||||
System.err.println("Client died...");
|
||||
clientException = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
clientThread.start();
|
||||
} else {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
* @run main/timeout=300 SupportedDSAParamGen 1024 160
|
||||
* @run main/timeout=300 SupportedDSAParamGen 2048 224
|
||||
* @run main/timeout=300 SupportedDSAParamGen 2048 256
|
||||
* @run main/timeout=450 SupportedDSAParamGen 3072 256
|
||||
* @run main/timeout=700 SupportedDSAParamGen 3072 256
|
||||
*/
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
@ -31,9 +31,6 @@ import java.security.NoSuchProviderException;
|
||||
import java.security.spec.DSAGenParameterSpec;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @test
|
||||
@ -43,8 +40,15 @@ import java.util.stream.Collectors;
|
||||
* DSA within some certain range of key sizes as described in the class
|
||||
* specification (L, N) as (1024, 160), (2048, 224), (2048, 256) and
|
||||
* (3072, 256) should be OK for DSAGenParameterSpec.
|
||||
* @run main TestDSAGenParameterSpec 2048,256,true 2048,224,true 1024,160,true 4096,256 3072,224 2048,160 1024,224 512,160
|
||||
* @run main TestDSAGenParameterSpec 3072,256,true
|
||||
* @run main TestDSAGenParameterSpec 512 160
|
||||
* @run main TestDSAGenParameterSpec 1024 160 true
|
||||
* @run main TestDSAGenParameterSpec 1024 224
|
||||
* @run main TestDSAGenParameterSpec 2048 160
|
||||
* @run main/timeout=300 TestDSAGenParameterSpec 2048 224 true
|
||||
* @run main/timeout=300 TestDSAGenParameterSpec 2048 256 true
|
||||
* @run main TestDSAGenParameterSpec 3072 224
|
||||
* @run main/timeout=700 TestDSAGenParameterSpec 3072 256 true
|
||||
* @run main TestDSAGenParameterSpec 4096 256
|
||||
*/
|
||||
public class TestDSAGenParameterSpec {
|
||||
|
||||
@ -57,8 +61,8 @@ public class TestDSAGenParameterSpec {
|
||||
System.out.printf("Test case: primePLen=%d, " + "subprimeQLen=%d%n",
|
||||
dataTuple.primePLen, dataTuple.subprimeQLen);
|
||||
|
||||
AlgorithmParameterGenerator apg =
|
||||
AlgorithmParameterGenerator.getInstance(ALGORITHM_NAME,
|
||||
AlgorithmParameterGenerator apg
|
||||
= AlgorithmParameterGenerator.getInstance(ALGORITHM_NAME,
|
||||
PROVIDER_NAME);
|
||||
|
||||
DSAGenParameterSpec genParamSpec = createGenParameterSpec(dataTuple);
|
||||
@ -80,8 +84,8 @@ public class TestDSAGenParameterSpec {
|
||||
|
||||
private static void checkParam(AlgorithmParameters param,
|
||||
DSAGenParameterSpec genParam) throws InvalidParameterSpecException,
|
||||
NoSuchAlgorithmException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException {
|
||||
NoSuchAlgorithmException, NoSuchProviderException,
|
||||
InvalidAlgorithmParameterException {
|
||||
String algorithm = param.getAlgorithm();
|
||||
if (!algorithm.equalsIgnoreCase(ALGORITHM_NAME)) {
|
||||
throw new RuntimeException(
|
||||
@ -139,21 +143,25 @@ public class TestDSAGenParameterSpec {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
List<DataTuple> dataTuples = Arrays.stream(args)
|
||||
.map(arg -> arg.split(",")).map(params -> {
|
||||
int primePLen = Integer.valueOf(params[0]);
|
||||
int subprimeQLen = Integer.valueOf(params[1]);
|
||||
boolean isDSASpecSupported = false;
|
||||
if (params.length == 3) {
|
||||
isDSASpecSupported = Boolean.valueOf(params[2]);
|
||||
}
|
||||
return new DataTuple(primePLen, subprimeQLen,
|
||||
isDSASpecSupported);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
for (DataTuple dataTuple : dataTuples) {
|
||||
testDSAGenParameterSpec(dataTuple);
|
||||
if (args == null || args.length < 2) {
|
||||
throw new RuntimeException("Invalid number of arguments to generate"
|
||||
+ " DSA parameter.");
|
||||
}
|
||||
DataTuple dataTuple = null;
|
||||
switch (args.length) {
|
||||
case 3:
|
||||
dataTuple = new DataTuple(Integer.valueOf(args[0]),
|
||||
Integer.valueOf(args[1]), Boolean.valueOf(args[2]));
|
||||
break;
|
||||
case 2:
|
||||
dataTuple = new DataTuple(Integer.valueOf(args[0]),
|
||||
Integer.valueOf(args[1]), false);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unsupported arguments found.");
|
||||
}
|
||||
testDSAGenParameterSpec(dataTuple);
|
||||
|
||||
}
|
||||
|
||||
private static class DataTuple {
|
||||
@ -170,4 +178,3 @@ public class TestDSAGenParameterSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,20 +22,25 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8051408
|
||||
* @bug 8051408 8157308
|
||||
* @modules java.base/sun.security.provider
|
||||
* @build java.base/sun.security.provider.S
|
||||
* @run main SpecTest
|
||||
* @summary check the AbstractDrbg API etc
|
||||
*/
|
||||
|
||||
import java.security.*;
|
||||
import sun.security.provider.AbstractDrbg;
|
||||
import sun.security.provider.S;
|
||||
import static java.security.DrbgParameters.Capability.*;
|
||||
|
||||
/**
|
||||
* This test makes sure the AbstractDrbg API works as specified. It also
|
||||
* checks the SecureRandom API.
|
||||
*
|
||||
* The implementations must be patched into java.base/sun.security.provider
|
||||
* because AbstractDrbg is not a public interface.
|
||||
*/
|
||||
public class AbstractDrbgSpec {
|
||||
public class SpecTest {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
@ -170,9 +175,9 @@ public class AbstractDrbgSpec {
|
||||
public static class All extends Provider {
|
||||
protected All(String name, double version, String info) {
|
||||
super(name, version, info);
|
||||
put("SecureRandom.S1", S1.class.getName());
|
||||
put("SecureRandom.S2", S2.class.getName());
|
||||
put("SecureRandom.S3", S3.class.getName());
|
||||
put("SecureRandom.S1", S.S1.class.getName());
|
||||
put("SecureRandom.S2", S.S2.class.getName());
|
||||
put("SecureRandom.S3", S.S3.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,92 +185,21 @@ public class AbstractDrbgSpec {
|
||||
public static class Legacy extends Provider {
|
||||
protected Legacy(String name, double version, String info) {
|
||||
super(name, version, info);
|
||||
put("SecureRandom.S", S1.class.getName());
|
||||
put("SecureRandom.S", S.S1.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Weak extends Provider {
|
||||
protected Weak(String name, double version, String info) {
|
||||
super(name, version, info);
|
||||
put("SecureRandom.S", S2.class.getName());
|
||||
put("SecureRandom.S", S.S2.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Strong extends Provider {
|
||||
protected Strong(String name, double version, String info) {
|
||||
super(name, version, info);
|
||||
put("SecureRandom.S", S3.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// This is not a DRBG.
|
||||
public static class S1 extends SecureRandomSpi {
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] seed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int numBytes) {
|
||||
return new byte[numBytes];
|
||||
}
|
||||
}
|
||||
|
||||
// This is a strong DRBG.
|
||||
public static class S3 extends AbstractDrbg {
|
||||
|
||||
public S3(SecureRandomParameters params) {
|
||||
supportPredictionResistance = true;
|
||||
supportReseeding = true;
|
||||
highestSupportedSecurityStrength = 192;
|
||||
mechName = "S3";
|
||||
algorithm = "SQUEEZE";
|
||||
configure(params);
|
||||
}
|
||||
protected void chooseAlgorithmAndStrength() {
|
||||
if (requestedInstantiationSecurityStrength < 0) {
|
||||
securityStrength = DEFAULT_STRENGTH;
|
||||
} else {
|
||||
securityStrength = requestedInstantiationSecurityStrength;
|
||||
}
|
||||
minLength = securityStrength / 8;
|
||||
maxAdditionalInputLength = maxPersonalizationStringLength = 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEngine() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void instantiateAlgorithm(byte[] ei) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateAlgorithm(byte[] result, byte[] additionalInput) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This is a weak DRBG. maximum strength is 128 and does
|
||||
// not support prediction resistance or reseed.
|
||||
public static class S2 extends S3 {
|
||||
public S2(SecureRandomParameters params) {
|
||||
super(null);
|
||||
mechName = "S2";
|
||||
highestSupportedSecurityStrength = 128;
|
||||
supportPredictionResistance = false;
|
||||
supportReseeding = false;
|
||||
configure(params);
|
||||
put("SecureRandom.S", S.S3.class.getName());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.SecureRandomParameters;
|
||||
import java.security.SecureRandomSpi;
|
||||
|
||||
/**
|
||||
* Read ../../../../SpecTest.java for details.
|
||||
*/
|
||||
public class S extends SecureRandomSpi {
|
||||
|
||||
protected AbstractDrbg impl;
|
||||
|
||||
// This is not a DRBG.
|
||||
public static class S1 extends SecureRandomSpi {
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] seed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int numBytes) {
|
||||
return new byte[numBytes];
|
||||
}
|
||||
}
|
||||
|
||||
// This is a weak DRBG. maximum strength is 128 and does
|
||||
// not support prediction resistance or reseed.
|
||||
public static class S2 extends S {
|
||||
public S2(SecureRandomParameters params) {
|
||||
impl = new Impl2(params);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a strong DRBG.
|
||||
public static class S3 extends S {
|
||||
public S3(SecureRandomParameters params) {
|
||||
impl = new Impl3(params);
|
||||
}
|
||||
}
|
||||
|
||||
// AbstractDrbg Implementations
|
||||
|
||||
static class Impl3 extends AbstractDrbg {
|
||||
|
||||
public Impl3(SecureRandomParameters params) {
|
||||
supportPredictionResistance = true;
|
||||
supportReseeding = true;
|
||||
highestSupportedSecurityStrength = 192;
|
||||
mechName = "S3";
|
||||
algorithm = "SQUEEZE";
|
||||
configure(params);
|
||||
}
|
||||
|
||||
protected void chooseAlgorithmAndStrength() {
|
||||
if (requestedInstantiationSecurityStrength < 0) {
|
||||
securityStrength = DEFAULT_STRENGTH;
|
||||
} else {
|
||||
securityStrength = requestedInstantiationSecurityStrength;
|
||||
}
|
||||
minLength = securityStrength / 8;
|
||||
maxAdditionalInputLength = maxPersonalizationStringLength = 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEngine() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void instantiateAlgorithm(byte[] ei) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateAlgorithm(byte[] result, byte[] additionalInput) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) {
|
||||
}
|
||||
}
|
||||
|
||||
static class Impl2 extends Impl3 {
|
||||
public Impl2(SecureRandomParameters params) {
|
||||
super(null);
|
||||
mechName = "S2";
|
||||
highestSupportedSecurityStrength = 128;
|
||||
supportPredictionResistance = false;
|
||||
supportReseeding = false;
|
||||
configure(params);
|
||||
}
|
||||
}
|
||||
|
||||
// Overridden SecureRandomSpi methods
|
||||
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] seed) {
|
||||
impl.engineSetSeed(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
impl.engineNextBytes(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int numBytes) {
|
||||
return impl.engineGenerateSeed(numBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(
|
||||
byte[] bytes, SecureRandomParameters params) {
|
||||
impl.engineNextBytes(bytes, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineReseed(SecureRandomParameters params) {
|
||||
impl.engineReseed(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SecureRandomParameters engineGetParameters() {
|
||||
return impl.engineGetParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return impl.toString();
|
||||
}
|
||||
}
|
70
jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java
Normal file
70
jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import sun.security.provider.DRBG;
|
||||
import sun.security.provider.MoreDrbgParameters;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8157308
|
||||
* @modules java.base/sun.security.provider
|
||||
* @summary Make AbstractDrbg non-Serializable
|
||||
* @run main DRBGS11n mech
|
||||
* @run main DRBGS11n capability
|
||||
*/
|
||||
public class DRBGS11n {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
DRBG d = new DRBG(null);
|
||||
Field f = DRBG.class.getDeclaredField("mdp");
|
||||
f.setAccessible(true);
|
||||
MoreDrbgParameters mdp = (MoreDrbgParameters)f.get(d);
|
||||
|
||||
// Corrupt the mech or capability fields inside DRBG#mdp.
|
||||
f = MoreDrbgParameters.class.getDeclaredField(args[0]);
|
||||
f.setAccessible(true);
|
||||
f.set(mdp, null);
|
||||
|
||||
try {
|
||||
revive(d);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// Expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception("revive should fail");
|
||||
}
|
||||
|
||||
static <T> T revive(T in) throws Exception {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
new ObjectOutputStream(bout).writeObject(in);
|
||||
return (T) new ObjectInputStream(
|
||||
new ByteArrayInputStream(bout.toByteArray())).readObject();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user