1 package software.amazon.awssdk.crt.eventstream; 2 3 import java.nio.ByteBuffer; 4 import java.util.ArrayList; 5 import java.util.List; 6 import java.util.concurrent.CompletableFuture; 7 8 /** 9 * Handler for EventStream ClientConnections. It's marked AutoClosable. 10 * By default onConnectionClosed, calls the close() function on this object. 11 */ 12 public abstract class ClientConnectionHandler implements AutoCloseable { 13 protected ClientConnection clientConnection; 14 ClientConnectionHandler()15 public ClientConnectionHandler() { 16 } 17 18 /** 19 * Invoked upon completion of the Connection attempt 20 * @param connection if the setup was successful, connection is non-null. On error, errorCode 21 * will be non-zero 22 * @param errorCode Error representing any error that occurred during connect. 23 */ onConnectionSetup(final ClientConnection connection, int errorCode)24 protected abstract void onConnectionSetup(final ClientConnection connection, int errorCode); 25 26 /** 27 * Invoked from JNI. Constructs usable ClientConnection object and invokes: 28 * onConnectionSetup() 29 */ onConnectionSetupShim(long connectionPtr, int errorCode)30 void onConnectionSetupShim(long connectionPtr, int errorCode) { 31 if (connectionPtr != 0) { 32 // don't add ref, this is a private constructor and the only reference lives in the handler. 33 clientConnection = new ClientConnection(connectionPtr); 34 } 35 36 onConnectionSetup(clientConnection, errorCode); 37 } 38 39 /** 40 * Invoked when a message is received on a connection. 41 * @param headers List of EventStream headers for the message received. 42 * @param payload Payload for the message received 43 * @param messageType message type for the message 44 * @param messageFlags message flags for the message 45 */ onProtocolMessage(final List<Header> headers, final byte[] payload, final MessageType messageType, int messageFlags)46 protected abstract void onProtocolMessage(final List<Header> headers, 47 final byte[] payload, final MessageType messageType, int messageFlags); 48 49 50 /** 51 * Invoked from JNI. Marshalls the native data into usable java objects and invokes 52 * onProtocolMessage() 53 */ onProtocolMessage(final byte[] headersPayload, final byte[] payload, int messageType, int messageFlags)54 private void onProtocolMessage(final byte[] headersPayload, final byte[] payload, 55 int messageType, int messageFlags) { 56 List<Header> headers = new ArrayList<>(); 57 58 ByteBuffer headersBuffer = ByteBuffer.wrap(headersPayload); 59 while (headersBuffer.hasRemaining()) { 60 Header header = Header.fromByteBuffer(headersBuffer); 61 headers.add(header); 62 } 63 64 onProtocolMessage(headers, payload, MessageType.fromEnumValue(messageType), messageFlags); 65 } 66 67 /** 68 * Invoked from JNI. Invokes onConnectionClosed() 69 */ onConnectionClosedShim(int closeReason)70 private void onConnectionClosedShim(int closeReason) { 71 onConnectionClosed(closeReason); 72 } 73 74 /** 75 * @return a future for syncing on Connection closed. 76 */ getConnectionClosedFuture()77 public CompletableFuture<Integer> getConnectionClosedFuture() { 78 return clientConnection.getClosedFuture(); 79 } 80 81 /** 82 * Invoked upon the connection closed event. By default it calls close() 83 * on this object. 84 * @param closeReason The reason the connection was closed. 0 means a clean shutdown. 85 */ onConnectionClosed(int closeReason)86 protected void onConnectionClosed(int closeReason) { 87 this.close(); 88 } 89 90 @Override close()91 public void close() { 92 if (clientConnection != null) { 93 if (clientConnection.isOpen()) { 94 clientConnection.closeConnection(0); 95 } 96 clientConnection.decRef(); 97 clientConnection = null; 98 } 99 } 100 } 101 102