Skip to content

Commit 576374b

Browse files
committed
docs: add http engine in-code docs
Also add algorithm how to add new engine in the `CONTRIBUTING.md` guide
1 parent 6f38c17 commit 576374b

8 files changed

Lines changed: 148 additions & 11 deletions

File tree

CONTRIBUTING.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ The Android-specific library AAR is built with:
3535

3636
(The `ANDROID_HOME` environment variable must be set appropriately.)
3737

38+
## Adding a New Network Engine Implementation
39+
40+
Currently, `ably-java` supports two different engines for network operations (HTTP calls and WebSocket connections):
41+
42+
- **Default Engine**: Utilizes the built-in `HttpUrlConnection` for HTTP calls and the TooTallNate/Java-WebSocket library for WebSocket connections.
43+
- **OkHttp Engine**: Utilizes the OkHttp library for both HTTP and WebSocket connections.
44+
45+
These engines are designed to be swappable. By default, the library comes with the default engine, but you can easily replace it with the OkHttp engine:
46+
47+
```kotlin
48+
implementation("io.ably:ably-java:$ABLY_VERSION") {
49+
exclude(group = "io.ably", module = "network-client-default")
50+
}
51+
runtimeOnly("io.ably:network-client-okhttp:$ABLY_VERSION")
52+
```
53+
54+
### How to Add a New Network Engine
55+
56+
To add a new network engine, follow these steps:
57+
58+
1. **Implement the interfaces**:
59+
- Implement the `HttpEngineFactory` and `WebSocketEngineFactory` interfaces for your custom engine.
60+
61+
2. **Register the engine**:
62+
- Modify the `getFirstAvailable()` methods in these interfaces to include your new implementation.
63+
64+
Once done, your custom network engine will be available for use within `ably-java`.
65+
3866
### Code Standard
3967

4068
#### Checkstyle
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
package io.ably.lib.network;
22

3+
/**
4+
* Cancelable Http request call
5+
* <p/>
6+
* Implementation should be thread-safe
7+
*/
38
public interface HttpCall {
9+
/**
10+
* Synchronously execute Http request and return response from te server
11+
*/
412
HttpResponse execute();
13+
14+
/**
15+
* Cancel pending Http request
16+
*/
517
void cancel();
618
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
package io.ably.lib.network;
22

3+
/**
4+
* An HTTP engine instance that can make cancelable HTTP requests.
5+
* It contains some engine-wide configurations, such as proxy settings,
6+
* if it operates under a corporate proxy.
7+
*/
38
public interface HttpEngine {
9+
/**
10+
* @return cancelable Http request call
11+
*/
412
HttpCall call(HttpRequest request);
13+
14+
/**
15+
* @return <code>true</code> if it uses proxy, <code>false</code> otherwise
16+
*/
517
boolean isUsingProxy();
618
}

network-client-core/src/main/java/io/ably/lib/network/HttpEngineFactory.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22

33
import java.lang.reflect.InvocationTargetException;
44

5+
/**
6+
* The <code>HttpEngineFactory</code> is a utility class that produces a common HTTP Engine API
7+
* for different implementations. Currently, it supports:
8+
* - HttpURLConnection ({@link EngineType#DEFAULT})
9+
* - OkHttp ({@link EngineType#OKHTTP})
10+
* <p>
11+
* Please note that all methods in <code>HttpEngineFactory</code> are static.
12+
*/
513
public interface HttpEngineFactory {
614

7-
HttpEngine create(HttpEngineConfig config);
8-
EngineType getEngineType();
9-
1015
static HttpEngineFactory getFirstAvailable() {
1116
HttpEngineFactory okHttpFactory = tryGetOkHttpFactory();
1217
if (okHttpFactory != null) return okHttpFactory;
@@ -19,7 +24,8 @@ static HttpEngineFactory tryGetOkHttpFactory() {
1924
try {
2025
Class<?> okHttpFactoryClass = Class.forName("io.ably.lib.network.OkHttpEngineFactory");
2126
return (HttpEngineFactory) okHttpFactoryClass.getDeclaredConstructor().newInstance();
22-
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
27+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
28+
InvocationTargetException e) {
2329
return null;
2430
}
2531
}
@@ -28,8 +34,13 @@ static HttpEngineFactory tryGetDefaultFactory() {
2834
try {
2935
Class<?> defaultFactoryClass = Class.forName("io.ably.lib.network.DefaultHttpEngineFactory");
3036
return (HttpEngineFactory) defaultFactoryClass.getDeclaredConstructor().newInstance();
31-
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
37+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
38+
InvocationTargetException e) {
3239
return null;
3340
}
3441
}
42+
43+
HttpEngine create(HttpEngineConfig config);
44+
45+
EngineType getEngineType();
3546
}

network-client-core/src/main/java/io/ably/lib/network/WebSocketClient.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package io.ably.lib.network;
22

3+
/**
4+
* WebSocketClient instance bind to the specified URI.
5+
* The connection will be established once you call <var>connect</var>.
6+
*/
37
public interface WebSocketClient {
48

9+
/**
10+
* Establish connection to the Websocket server
11+
*/
512
void connect();
613

714
/**
@@ -12,7 +19,7 @@ public interface WebSocketClient {
1219
/**
1320
* Sends the closing handshake. May be sent in response to any other handshake.
1421
*
15-
* @param code the closing code
22+
* @param code the closing code
1623
* @param reason the closing message
1724
*/
1825
void close(int code, String reason);
@@ -21,13 +28,23 @@ public interface WebSocketClient {
2128
* This will close the connection immediately without a proper close handshake. The code and the
2229
* message therefore won't be transferred over the wire also they will be forwarded to `onClose`.
2330
*
24-
* @param code the closing code
31+
* @param code the closing code
2532
* @param reason the closing message
2633
**/
2734
void cancel(int code, String reason);
2835

36+
/**
37+
* Sends binary <var>message</var> to the connected webSocket server.
38+
*
39+
* @param message The byte-Array of data to send to the WebSocket server.
40+
*/
2941
void send(byte[] message);
3042

43+
/**
44+
* Sends <var>message</var> to the connected websocket server.
45+
*
46+
* @param message The string which will be transmitted.
47+
*/
3148
void send(String message);
3249

3350
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package io.ably.lib.network;
22

3+
/**
4+
* Create WebSocket client bind to the specific URL
5+
*/
36
public interface WebSocketEngine {
47
WebSocketClient create(String url, WebSocketListener listener);
58
}

network-client-core/src/main/java/io/ably/lib/network/WebSocketEngineFactory.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22

33
import java.lang.reflect.InvocationTargetException;
44

5+
/**
6+
* The <code>WebSocketEngineFactory</code> is a utility class that produces a common WebSocket Engine API
7+
* for different implementations. Currently, it supports:
8+
* - TooTallNate/Java-WebSocket ({@link EngineType#DEFAULT})
9+
* - OkHttp ({@link EngineType#OKHTTP})
10+
* <p>
11+
* Please note that all methods in <code>WebSocketEngineFactory</code> are static.
12+
*/
513
public interface WebSocketEngineFactory {
6-
WebSocketEngine create(WebSocketEngineConfig config);
7-
EngineType getEngineType();
8-
914
static WebSocketEngineFactory getFirstAvailable() {
1015
WebSocketEngineFactory okWebSocketFactory = tryGetOkWebSocketFactory();
1116
if (okWebSocketFactory != null) return okWebSocketFactory;
@@ -28,8 +33,13 @@ static WebSocketEngineFactory tryGetDefaultFactory() {
2833
try {
2934
Class<?> defaultFactoryClass = Class.forName("io.ably.lib.network.DefaultWebSocketEngineFactory");
3035
return (WebSocketEngineFactory) defaultFactoryClass.getDeclaredConstructor().newInstance();
31-
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
36+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
37+
InvocationTargetException e) {
3238
return null;
3339
}
3440
}
41+
42+
WebSocketEngine create(WebSocketEngineConfig config);
43+
44+
EngineType getEngineType();
3545
}

network-client-core/src/main/java/io/ably/lib/network/WebSocketListener.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,56 @@
22

33
import java.nio.ByteBuffer;
44

5+
/**
6+
* WebSocket Listener
7+
*/
58
public interface WebSocketListener {
9+
/**
10+
* Called after an opening handshake has been performed and the given websocket is ready to be
11+
* written on.
12+
*/
613
void onOpen();
14+
15+
/**
16+
* Callback for binary messages received from the remote host
17+
*
18+
* @param blob The binary message that was received.
19+
* @see #onMessage(String)
20+
**/
721
void onMessage(ByteBuffer blob);
22+
23+
/**
24+
* Callback for string messages received from the remote host
25+
*
26+
* @param string The UTF-8 decoded message that was received.
27+
* @see #onMessage(ByteBuffer)
28+
**/
829
void onMessage(String string);
30+
31+
/**
32+
* Callback for receiving ping frame if it supported by websocket engine
33+
*/
934
void onWebsocketPing();
35+
36+
/**
37+
* Called after the websocket connection has been closed.
38+
*
39+
* @param reason Additional information string
40+
**/
1041
void onClose(int code, String reason);
42+
43+
/**
44+
* Called when errors occurs. If an error causes the websocket connection to fail {@link
45+
* WebSocketListener#onClose(int, String)} will be called additionally.<br> This method will be called
46+
* primarily because of IO or protocol errors.<br> If the given exception is an RuntimeException
47+
* that probably means that you encountered a bug.<br>
48+
*
49+
* @param throwable The exception causing this error
50+
**/
1151
void onError(Throwable throwable);
52+
53+
/**
54+
* We invoke this callback when runtime is not able to use secure https algorithms (TLS 1.2 +)
55+
*/
1256
void onOldJavaVersionDetected(Throwable throwable);
1357
}

0 commit comments

Comments
 (0)