//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

[[websocket-jetty-api-send-message]]
=== Send Messages to Remote Endpoint

The most important feature of the Session is access to the link:{JDURL}/org/eclipse/jetty/websocket/api/RemoteEndpoint.html[`org.eclipse.jetty.websocket.api.RemoteEndpoint`] needed to send messages.

With RemoteEndpoint you can choose to send TEXT or BINARY WebSocket messages, or the WebSocket PING and PONG control frames.

[[blocking]]
==== Blocking Send Message

Most calls are blocking in nature, and will not return until the send has completed (or has thrown an exception).

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Blocking Send of a BINARY message to remote endpoint
ByteBuffer buf = ByteBuffer.wrap(new byte[] { 0x11, 0x22, 0x33, 0x44 });
try
{
    remote.sendBytes(buf);
}
catch (IOException e)
{
    e.printStackTrace(System.err);
}
----

How to send a simple Binary message using the RemoteEndpoint.
This will block until the message is sent, possibly throwing an IOException if unable to send the message.

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Blocking Send of a TEXT message to remote endpoint
try
{
    remote.sendString("Hello World");
}
catch (IOException e)
{
    e.printStackTrace(System.err);
}
----

How to send a simple Text message using the RemoteEndpoint.
This will block until the message is sent, possibly throwing an IOException if unable to send the message.

[[partial]]
==== Send Partial Message

If you have a large message to send, and want to send it in pieces and parts, you can utilize the partial message sending methods of RemoteEndpoint.
Just be sure you finish sending your message (`isLast == true`).

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Blocking Send of a BINARY message to remote endpoint
// Part 1
ByteBuffer buf1 = ByteBuffer.wrap(new byte[] { 0x11, 0x22 });
// Part 2 (last part)
ByteBuffer buf2 = ByteBuffer.wrap(new byte[] { 0x33, 0x44 });
try
{
    remote.sendPartialBytes(buf1,false);
    remote.sendPartialBytes(buf2,true); // isLast is true
}
catch (IOException e)
{
    e.printStackTrace(System.err);
}
----

How to send a Binary message in 2 parts, using the partial message support in RemoteEndpoint.
This will block until each part of the message is sent, possibly throwing an IOException if unable to send the partial message.

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Blocking Send of a TEXT message to remote endpoint
String part1 = "Hello";
String part2 = " World";
try
{
    remote.sendPartialString(part1,false);
    remote.sendPartialString(part2,true); // last part
}
catch (IOException e)
{
    e.printStackTrace(System.err);
}
----

How to send a Text message in 2 parts, using the partial message support in RemoteEndpoint.
This will block until each part of the message is sent, possibly throwing an IOException if unable to send the partial message.

[[websocket-async-send]]
==== Async Send Message

There are also four (4) async send message methods available:

* link:{JDURL}/org/eclipse/jetty/websocket/api/RemoteEndpoint.html#sendBytes(java.nio.ByteBuffer,org.eclipse.jetty.websocket.api.WriteCallback)[`RemoteEndpoint.sendBytes(ByteBuffer message, WriteCallback callback)`]
* link:{JDURL}/org/eclipse/jetty/websocket/api/RemoteEndpoint.html#sendPartialBytes(java.nio.ByteBuffer,boolean,org.eclipse.jetty.websocket.api.WriteCallback)[`RemoteEndpoint.sendPartialBytes(ByteBuffer message, boolean isLast, WriteCallback callback)`]
* link:{JDURL}/org/eclipse/jetty/websocket/api/RemoteEndpoint.html#sendString(java.lang.String,org.eclipse.jetty.websocket.api.WriteCallback)[`RemoteEndpoint.sendString(String message, WriteCallback callback)`]
* link:{JDURL}/org/eclipse/jetty/websocket/api/RemoteEndpoint.html#sendPartialString(java.lang.String,boolean,org.eclipse.jetty.websocket.api.WriteCallback)[`RemoteEndpoint.sendPartialString(String message, boolean isLast, WriteCallback callback)`]

All these async send methods use `WriteCallback`, which allows you to be notified when the write either succeeds or fails.

[source, java, subs="{sub-order}"]
----
WriteCallback callback = new WriteCallback()
{
    @Override
    public void writeSuccess()
    {
        // Notification that the write has succeeded.
    }

    @Override
    public void writeFailed(Throwable x)
    {
       // Notification that the write has failed.
       t.printStackTrace();
    }
};
----

The async send methods can be used in a similar way to the blocking send methods, however the method will return before the message is transmitted, and you are notified of the final result of the message transmission through the `WriteCallback`.
The static `WriteCallback.NOOP` can be used to do nothing on success / failure of the callback.

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Async Send of a BINARY message to remote endpoint
ByteBuffer message = ByteBuffer.wrap(new byte[] { 0x11, 0x22, 0x33, 0x44 });
remote.sendBytes(message, callback);
----


[[pingpong]]
==== Send Ping / Pong Control Frame

You can also send Ping and Pong control frames using the `RemoteEndpoint`.

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Blocking Send of a PING to remote endpoint
String data = "You There?";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
try
{
    remote.sendPing(payload);
}
catch (IOException e)
{
    e.printStackTrace(System.err);
}
----

How to send a Ping control frame, with a payload of `"You There?"` (arriving at Remote Endpoint as a byte array payload).
This will block until the message is sent, possibly throwing an `IOException` if unable to send the ping frame.

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

// Blocking Send of a PONG to remote endpoint
String data = "Yup, I'm here";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
try
{
    remote.sendPong(payload);
}
catch (IOException e)
{
    e.printStackTrace(System.err);
}
----

How to send a Pong control frame, with a payload of `"Yup I'm here"` (arriving at Remote Endpoint as a byte array payload).
This will block until the message is sent, possibly throwing an `IOException` if unable to send the pong frame.

To be correct in your usage of Pong frames, you should return the same byte array data that you received in the Ping frame.

You can also asynchronously send Ping and Pong frames using the `WriteCallback`, this will return before the Ping/Pong is
transmitted and notify you of the result in `WriteCallback` `writeSuccess()` or `writeFailed()`.

[source, java, subs="{sub-order}"]
----
RemoteEndpoint remote = session.getRemote();

String pingData = "You There?";
ByteBuffer pingPayload = ByteBuffer.wrap(data.getBytes());

String pongData = "Yup, I'm here";
ByteBuffer pongPayload = ByteBuffer.wrap(data.getBytes());

remote.sendPing(pingPayload, WriteCallback.NOOP);
remote.sendPong(pongPayload, WriteCallback.NOOP);
----
