8250839: Improve test template SSLEngineTemplate with SSLContextTemplate

Reviewed-by: ascarpino
diff --git a/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java b/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java
index 32470d1..24ff8e0 100644
--- a/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java
+++ b/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,15 @@
 
 /*
  * @test
- * @bug 1234567
- * @summary SSLEngine has not yet caused Solaris kernel to panic
+ * @bug 8250839
+ * @summary Improve test template SSLEngineTemplate with SSLContextTemplate
+ * @build SSLContextTemplate
  * @run main/othervm SSLEngineTemplate
  */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import java.nio.ByteBuffer;
+
 /**
  * A SSLEngine usage example which simplifies the presentation
  * by removing the I/O and multi-threading concerns.
@@ -44,231 +49,139 @@
  *
  * When this application runs, notice that several messages
  * (wrap/unwrap) pass before any application data is consumed or
- * produced.  (For more information, please see the SSL/TLS
- * specifications.)  There may several steps for a successful handshake,
- * so it's typical to see the following series of operations:
- *
- *      client          server          message
- *      ======          ======          =======
- *      wrap()          ...             ClientHello
- *      ...             unwrap()        ClientHello
- *      ...             wrap()          ServerHello/Certificate
- *      unwrap()        ...             ServerHello/Certificate
- *      wrap()          ...             ClientKeyExchange
- *      wrap()          ...             ChangeCipherSpec
- *      wrap()          ...             Finished
- *      ...             unwrap()        ClientKeyExchange
- *      ...             unwrap()        ChangeCipherSpec
- *      ...             unwrap()        Finished
- *      ...             wrap()          ChangeCipherSpec
- *      ...             wrap()          Finished
- *      unwrap()        ...             ChangeCipherSpec
- *      unwrap()        ...             Finished
+ * produced.
  */
-import javax.net.ssl.*;
-import javax.net.ssl.SSLEngineResult.*;
-import java.io.*;
-import java.security.*;
-import java.nio.*;
+public class SSLEngineTemplate implements SSLContextTemplate {
+    private final SSLEngine clientEngine;     // client Engine
+    private final ByteBuffer clientOut;       // write side of clientEngine
+    private final ByteBuffer clientIn;        // read side of clientEngine
 
-public class SSLEngineTemplate {
+    private final SSLEngine serverEngine;     // server Engine
+    private final ByteBuffer serverOut;       // write side of serverEngine
+    private final ByteBuffer serverIn;        // read side of serverEngine
+
+    // For data transport, this example uses local ByteBuffers.  This
+    // isn't really useful, but the purpose of this example is to show
+    // SSLEngine concepts, not how to do network transport.
+    private final ByteBuffer cTOs;      // "reliable" transport client->server
+    private final ByteBuffer sTOc;      // "reliable" transport server->client
+
+    private SSLEngineTemplate() throws Exception {
+        serverEngine = configureServerEngine(
+                createServerSSLContext().createSSLEngine());
+
+        clientEngine = configureClientEngine(
+                createClientSSLContext().createSSLEngine());
+
+        // We'll assume the buffer sizes are the same
+        // between client and server.
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        // We'll make the input buffers a bit bigger than the max needed
+        // size, so that unwrap()s following a successful data transfer
+        // won't generate BUFFER_OVERFLOWS.
+        //
+        // We'll use a mix of direct and indirect ByteBuffers for
+        // tutorial purposes only.  In reality, only use direct
+        // ByteBuffers when they give a clear performance enhancement.
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    //
+    // Protected methods could be used to customize the test case.
+    //
 
     /*
-     * Enables logging of the SSLEngine operations.
+     * Configure the client side engine.
      */
-    private static final boolean logging = true;
+    protected SSLEngine configureClientEngine(SSLEngine clientEngine) {
+        clientEngine.setUseClientMode(true);
 
-    /*
-     * Enables the JSSE system debugging system property:
-     *
-     *     -Djavax.net.debug=all
-     *
-     * This gives a lot of low-level information about operations underway,
-     * including specific handshake messages, and might be best examined
-     * after gaining some familiarity with this application.
-     */
-    private static final boolean debug = false;
+        // Get/set parameters if needed
+        // SSLParameters paramsClient = clientEngine.getSSLParameters();
+        // clientEngine.setSSLParameters(paramsClient);
 
-    private final SSLContext sslc;
-
-    private SSLEngine clientEngine;     // client Engine
-    private ByteBuffer clientOut;       // write side of clientEngine
-    private ByteBuffer clientIn;        // read side of clientEngine
-
-    private SSLEngine serverEngine;     // server Engine
-    private ByteBuffer serverOut;       // write side of serverEngine
-    private ByteBuffer serverIn;        // read side of serverEngine
-
-    /*
-     * For data transport, this example uses local ByteBuffers.  This
-     * isn't really useful, but the purpose of this example is to show
-     * SSLEngine concepts, not how to do network transport.
-     */
-    private ByteBuffer cTOs;            // "reliable" transport client->server
-    private ByteBuffer sTOc;            // "reliable" transport server->client
-
-    /*
-     * The following is to set up the keystores.
-     */
-    private static final String pathToStores = "../etc";
-    private static final String keyStoreFile = "keystore";
-    private static final String trustStoreFile = "truststore";
-    private static final char[] passphrase = "passphrase".toCharArray();
-
-    private static final String keyFilename =
-            System.getProperty("test.src", ".") + "/" + pathToStores +
-                "/" + keyStoreFile;
-    private static final String trustFilename =
-            System.getProperty("test.src", ".") + "/" + pathToStores +
-                "/" + trustStoreFile;
-
-    /*
-     * Main entry point for this test.
-     */
-    public static void main(String args[]) throws Exception {
-        if (debug) {
-            System.setProperty("javax.net.debug", "all");
-        }
-
-        SSLEngineTemplate test = new SSLEngineTemplate();
-        test.runTest();
-
-        System.out.println("Test Passed.");
+        return clientEngine;
     }
 
     /*
-     * Create an initialized SSLContext to use for these tests.
+     * Configure the server side engine.
      */
-    public SSLEngineTemplate() throws Exception {
+    protected SSLEngine configureServerEngine(SSLEngine serverEngine) {
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(true);
 
-        KeyStore ks = KeyStore.getInstance("JKS");
-        KeyStore ts = KeyStore.getInstance("JKS");
+        // Get/set parameters if needed
+        //
+        // SSLParameters paramsServer = serverEngine.getSSLParameters();
+        // serverEngine.setSSLParameters(paramsServer);
 
-        ks.load(new FileInputStream(keyFilename), passphrase);
-        ts.load(new FileInputStream(trustFilename), passphrase);
-
-        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
-        kmf.init(ks, passphrase);
-
-        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
-        tmf.init(ts);
-
-        SSLContext sslCtx = SSLContext.getInstance("TLS");
-
-        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
-
-        sslc = sslCtx;
+        return serverEngine;
     }
 
-    /*
-     * Run the test.
-     *
-     * Sit in a tight loop, both engines calling wrap/unwrap regardless
-     * of whether data is available or not.  We do this until both engines
-     * report back they are closed.
-     *
-     * The main loop handles all of the I/O phases of the SSLEngine's
-     * lifetime:
-     *
-     *     initial handshaking
-     *     application data transfer
-     *     engine closing
-     *
-     * One could easily separate these phases into separate
-     * sections of code.
-     */
+    public static void main(String[] args) throws Exception {
+        new SSLEngineTemplate().runTest();
+    }
+
+    //
+    // Private methods that used to build the common part of the test.
+    //
+
     private void runTest() throws Exception {
-        boolean dataDone = false;
-
-        createSSLEngines();
-        createBuffers();
-
-        // results from client's last operation
         SSLEngineResult clientResult;
-
-        // results from server's last operation
         SSLEngineResult serverResult;
 
-        /*
-         * Examining the SSLEngineResults could be much more involved,
-         * and may alter the overall flow of the application.
-         *
-         * For example, if we received a BUFFER_OVERFLOW when trying
-         * to write to the output pipe, we could reallocate a larger
-         * pipe, but instead we wait for the peer to drain it.
-         */
-        Exception clientException = null;
-        Exception serverException = null;
+        boolean dataDone = false;
+        while (isOpen(clientEngine) || isOpen(serverEngine)) {
+            log("=================");
 
-        while (!isEngineClosed(clientEngine)
-                || !isEngineClosed(serverEngine)) {
-
-            log("================");
-
-            try {
-                clientResult = clientEngine.wrap(clientOut, cTOs);
-                log("client wrap: ", clientResult);
-            } catch (Exception e) {
-                clientException = e;
-                System.out.println("Client wrap() threw: " + e.getMessage());
-            }
-            logEngineStatus(clientEngine);
+            // client wrap
+            log("---Client Wrap---");
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            logEngineStatus(clientEngine, clientResult);
             runDelegatedTasks(clientEngine);
 
-            log("----");
-
-            try {
-                serverResult = serverEngine.wrap(serverOut, sTOc);
-                log("server wrap: ", serverResult);
-            } catch (Exception e) {
-                serverException = e;
-                System.out.println("Server wrap() threw: " + e.getMessage());
-            }
-            logEngineStatus(serverEngine);
+            // server wrap
+            log("---Server Wrap---");
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            logEngineStatus(serverEngine, serverResult);
             runDelegatedTasks(serverEngine);
 
             cTOs.flip();
             sTOc.flip();
 
-            log("--------");
-
-            try {
-                clientResult = clientEngine.unwrap(sTOc, clientIn);
-                log("client unwrap: ", clientResult);
-            } catch (Exception e) {
-                clientException = e;
-                System.out.println("Client unwrap() threw: " + e.getMessage());
-            }
-            logEngineStatus(clientEngine);
+            // client unwrap
+            log("---Client Unwrap---");
+            clientResult = clientEngine.unwrap(sTOc, clientIn);
+            logEngineStatus(clientEngine, clientResult);
             runDelegatedTasks(clientEngine);
 
-            log("----");
-
-            try {
-                serverResult = serverEngine.unwrap(cTOs, serverIn);
-                log("server unwrap: ", serverResult);
-            } catch (Exception e) {
-                serverException = e;
-                System.out.println("Server unwrap() threw: " + e.getMessage());
-            }
-            logEngineStatus(serverEngine);
+            // server unwrap
+            log("---Server Unwrap---");
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            logEngineStatus(serverEngine, serverResult);
             runDelegatedTasks(serverEngine);
 
             cTOs.compact();
             sTOc.compact();
 
-            /*
-             * After we've transfered all application data between the client
-             * and server, we close the clientEngine's outbound stream.
-             * This generates a close_notify handshake message, which the
-             * server engine receives and responds by closing itself.
-             */
+            // After we've transferred all application data between the client
+            // and server, we close the clientEngine's outbound stream.
+            // This generates a close_notify handshake message, which the
+            // server engine receives and responds by closing itself.
             if (!dataDone && (clientOut.limit() == serverIn.position()) &&
                     (serverOut.limit() == clientIn.position())) {
 
-                /*
-                 * A sanity check to ensure we got what was sent.
-                 */
+                // A sanity check to ensure we got what was sent.
                 checkTransfer(serverOut, clientIn);
                 checkTransfer(clientOut, serverIn);
 
@@ -284,78 +197,33 @@
         }
     }
 
+    private static boolean isOpen(SSLEngine engine) {
+        return (!engine.isOutboundDone() || !engine.isInboundDone());
+    }
+
     private static void logEngineStatus(SSLEngine engine) {
-        log("\tCurrent HS State  " + engine.getHandshakeStatus().toString());
-        log("\tisInboundDone():  " + engine.isInboundDone());
+        log("\tCurrent HS State: " + engine.getHandshakeStatus());
+        log("\tisInboundDone() : " + engine.isInboundDone());
         log("\tisOutboundDone(): " + engine.isOutboundDone());
     }
 
-    /*
-     * Using the SSLContext created during object creation,
-     * create/configure the SSLEngines we'll use for this test.
-     */
-    private void createSSLEngines() throws Exception {
-        /*
-         * Configure the serverEngine to act as a server in the SSL/TLS
-         * handshake.  Also, require SSL client authentication.
-         */
-        serverEngine = sslc.createSSLEngine();
-        serverEngine.setUseClientMode(false);
-        serverEngine.setNeedClientAuth(true);
-
-        // Get/set parameters if needed
-        SSLParameters paramsServer = serverEngine.getSSLParameters();
-        serverEngine.setSSLParameters(paramsServer);
-
-        /*
-         * Similar to above, but using client mode instead.
-         */
-        clientEngine = sslc.createSSLEngine("client", 80);
-        clientEngine.setUseClientMode(true);
-
-        // Get/set parameters if needed
-        SSLParameters paramsClient = clientEngine.getSSLParameters();
-        clientEngine.setSSLParameters(paramsClient);
+    private static void logEngineStatus(
+            SSLEngine engine, SSLEngineResult result) {
+        log("\tResult Status    : " + result.getStatus());
+        log("\tResult HS Status : " + result.getHandshakeStatus());
+        log("\tEngine HS Status : " + engine.getHandshakeStatus());
+        log("\tisInboundDone()  : " + engine.isInboundDone());
+        log("\tisOutboundDone() : " + engine.isOutboundDone());
+        log("\tMore Result      : " + result);
     }
 
-    /*
-     * Create and size the buffers appropriately.
-     */
-    private void createBuffers() {
-
-        /*
-         * We'll assume the buffer sizes are the same
-         * between client and server.
-         */
-        SSLSession session = clientEngine.getSession();
-        int appBufferMax = session.getApplicationBufferSize();
-        int netBufferMax = session.getPacketBufferSize();
-
-        /*
-         * We'll make the input buffers a bit bigger than the max needed
-         * size, so that unwrap()s following a successful data transfer
-         * won't generate BUFFER_OVERFLOWS.
-         *
-         * We'll use a mix of direct and indirect ByteBuffers for
-         * tutorial purposes only.  In reality, only use direct
-         * ByteBuffers when they give a clear performance enhancement.
-         */
-        clientIn = ByteBuffer.allocate(appBufferMax + 50);
-        serverIn = ByteBuffer.allocate(appBufferMax + 50);
-
-        cTOs = ByteBuffer.allocateDirect(netBufferMax);
-        sTOc = ByteBuffer.allocateDirect(netBufferMax);
-
-        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
-        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    private static void log(String message) {
+        System.err.println(message);
     }
 
-    /*
-     * If the result indicates that we have outstanding tasks to do,
-     * go ahead and run them in this thread.
-     */
+    // If the result indicates that we have outstanding tasks to do,
+    // go ahead and run them in this thread.
     private static void runDelegatedTasks(SSLEngine engine) throws Exception {
-
         if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
             Runnable runnable;
             while ((runnable = engine.getDelegatedTask()) != null) {
@@ -365,19 +233,13 @@
             HandshakeStatus hsStatus = engine.getHandshakeStatus();
             if (hsStatus == HandshakeStatus.NEED_TASK) {
                 throw new Exception(
-                    "handshake shouldn't need additional tasks");
+                        "handshake shouldn't need additional tasks");
             }
             logEngineStatus(engine);
         }
     }
 
-    private static boolean isEngineClosed(SSLEngine engine) {
-        return (engine.isOutboundDone() && engine.isInboundDone());
-    }
-
-    /*
-     * Simple check to make sure everything came across as expected.
-     */
+    // Simple check to make sure everything came across as expected.
     private static void checkTransfer(ByteBuffer a, ByteBuffer b)
             throws Exception {
         a.flip();
@@ -394,35 +256,4 @@
         a.limit(a.capacity());
         b.limit(b.capacity());
     }
-
-    /*
-     * Logging code
-     */
-    private static boolean resultOnce = true;
-
-    private static void log(String str, SSLEngineResult result) {
-        if (!logging) {
-            return;
-        }
-        if (resultOnce) {
-            resultOnce = false;
-            System.out.println("The format of the SSLEngineResult is: \n" +
-                    "\t\"getStatus() / getHandshakeStatus()\" +\n" +
-                    "\t\"bytesConsumed() / bytesProduced()\"\n");
-        }
-        HandshakeStatus hsStatus = result.getHandshakeStatus();
-        log(str +
-                result.getStatus() + "/" + hsStatus + ", " +
-                result.bytesConsumed() + "/" + result.bytesProduced() +
-                " bytes");
-        if (hsStatus == HandshakeStatus.FINISHED) {
-            log("\t...ready for application data");
-        }
-    }
-
-    private static void log(String str) {
-        if (logging) {
-            System.out.println(str);
-        }
-    }
 }