Skip to content

Commit a4f2aa6

Browse files
committed
documented the public APIs for main functions
1 parent 56e3931 commit a4f2aa6

11 files changed

Lines changed: 387 additions & 62 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The Java client library for interacting with Danube Messaging Broker platform.
4545

4646
```xml
4747
<dependency>
48-
<groupId>com.danubemessaging</groupId>
48+
<groupId>com.danube-messaging</groupId>
4949
<artifactId>danube-client</artifactId>
5050
<version>0.2.0</version>
5151
</dependency>
@@ -54,7 +54,7 @@ The Java client library for interacting with Danube Messaging Broker platform.
5454
### Gradle
5555

5656
```groovy
57-
implementation 'com.danubemessaging:danube-client:0.2.0'
57+
implementation 'com.danube-messaging:danube-client:0.2.0'
5858
```
5959

6060
**Requirements:** Java 21 or later.
@@ -225,7 +225,7 @@ docker compose ps
225225

226226
# 3. Run the integration tests from the repository root
227227
cd ..
228-
mvn -pl danube-client -Pfailsafe verify
228+
mvn -pl danube-client -Pintegration-tests verify
229229

230230
# 4. Stop the cluster when done
231231
cd docker/

RELEASE.md

Lines changed: 113 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,155 @@
11
# Release guide (Maven Central)
22

3-
This project is configured for Sonatype OSSRH publishing under the `release` Maven profile.
3+
This project publishes to Maven Central via the **Sonatype Central Portal** (`central.sonatype.com`).
4+
The `release` Maven profile handles sources jar, javadoc jar, GPG signing, and upload automatically.
45

5-
## 1) Prerequisites
6+
---
67

7-
1. Sonatype OSSRH account with publish access for `com.danubemessaging`.
8-
2. GPG key pair available locally.
9-
3. `~/.m2/settings.xml` configured with server credentials:
8+
## 1) One-time setup: Central Portal account
9+
10+
> Skip this section if the account already exists.
11+
12+
1. Go to **https://central.sonatype.com** and sign up (GitHub SSO works).
13+
2. Click **Namespaces****Add Namespace**.
14+
3. Enter `com.danube-messaging`.
15+
4. Sonatype will show a **DNS TXT verification token**. Add it to the `danube-messaging.com` DNS:
16+
```
17+
TXT @ sonatype-central-verification=<token>
18+
```
19+
5. Click **Verify Namespace**. Once verified the namespace is permanently linked to your account.
20+
21+
---
22+
23+
## 2) One-time setup: Portal user token (credentials)
24+
25+
1. In the Central Portal: **Account****Generate User Token**.
26+
2. Copy the `username` and `password` values shown.
27+
3. Add them to `~/.m2/settings.xml`:
1028

1129
```xml
1230
<settings>
1331
<servers>
1432
<server>
15-
<id>ossrh</id>
16-
<username>${env.OSSRH_USERNAME}</username>
17-
<password>${env.OSSRH_PASSWORD}</password>
33+
<id>central</id>
34+
<username>YOUR_TOKEN_USERNAME</username>
35+
<password>YOUR_TOKEN_PASSWORD</password>
1836
</server>
1937
</servers>
2038
</settings>
2139
```
2240

23-
4. Environment variables set for CI/local release:
41+
> **Never** commit these credentials. Use environment variable substitution if needed:
42+
> ```xml
43+
> <username>${env.CENTRAL_TOKEN_USERNAME}</username>
44+
> <password>${env.CENTRAL_TOKEN_PASSWORD}</password>
45+
> ```
46+
47+
---
48+
49+
## 3) One-time setup: GPG signing key
2450
2551
```bash
26-
export OSSRH_USERNAME=...
27-
export OSSRH_PASSWORD=...
28-
export GPG_TTY=$(tty)
52+
# Generate a key (if you don't have one)
53+
gpg --gen-key
54+
55+
# List keys and note the key ID
56+
gpg --list-secret-keys --keyid-format=long
57+
58+
# Publish the public key to a keyserver
59+
gpg --keyserver keyserver.ubuntu.com --send-keys <KEY_ID>
2960
```
3061
31-
If using passphrase-based signing in CI, also pass:
62+
Set the passphrase in your environment for headless signing:
3263

3364
```bash
34-
-Dgpg.passphrase=...
65+
export GPG_TTY=$(tty)
3566
```
3667

37-
## 2) Local verification (no deploy)
68+
---
69+
70+
## 4) Local verification (no deploy)
71+
72+
Before publishing, verify that all artifacts build and sign correctly:
3873

3974
```bash
4075
mvn -Prelease -DskipTests verify
4176
```
4277

43-
This validates source jar, javadoc jar, and artifact signing configuration.
78+
This produces and signs:
79+
- `danube-client-proto-0.2.0.jar` + sources + javadoc
80+
- `danube-client-0.2.0.jar` + sources + javadoc
4481

45-
## 3) Publish snapshot
82+
---
83+
84+
## 5) Publish release version
85+
86+
1. Confirm root `pom.xml` version is `0.2.0` (no `-SNAPSHOT` suffix).
87+
2. Commit and tag the release:
88+
89+
```bash
90+
git add -A
91+
git commit -m "release: v0.2.0"
92+
git tag v0.2.0
93+
git push origin main --tags
94+
```
95+
96+
3. Deploy to Maven Central:
4697

4798
```bash
4899
mvn -Prelease -DskipTests deploy
49100
```
50101

51-
For `-SNAPSHOT` versions this publishes to:
102+
Both `danube-client-proto` and `danube-client` are published in one command (multi-module build).
103+
The `central-publishing-maven-plugin` uploads, validates, and releases automatically
104+
(`autoPublish=true`, `waitUntil=published`). Artifacts are typically searchable within 30 minutes.
105+
106+
If GPG passphrase entry is required during deployment:
107+
108+
```bash
109+
mvn -Prelease -DskipTests -Dgpg.passphrase=YOUR_PASSPHRASE deploy
110+
```
52111

53-
- `https://s01.oss.sonatype.org/content/repositories/snapshots`
112+
---
54113

55-
## 4) Publish release version
114+
## 6) After release
56115

57-
1. Update root `<version>` from `x.y.z-SNAPSHOT` to `x.y.z`.
58-
2. Commit and tag the release.
59-
3. Run:
116+
1. Bump to the next development version:
60117

61118
```bash
62-
mvn -Prelease -DskipTests deploy
119+
# In pom.xml, danube-client/pom.xml, danube-client-proto/pom.xml
120+
# Change version: 0.2.0 → 0.3.0-SNAPSHOT
121+
```
122+
123+
2. Commit and push:
124+
125+
```bash
126+
git add -A
127+
git commit -m "chore: bump to 0.3.0-SNAPSHOT"
128+
git push origin main
63129
```
64130

65-
Release artifacts are staged and closed/released automatically via `nexus-staging-maven-plugin`.
131+
---
132+
133+
## CI/CD (GitHub Actions)
66134

67-
## 5) After release
135+
To automate publishing from CI, set these repository secrets:
68136

69-
1. Bump to next development version (e.g. `x.y.(z+1)-SNAPSHOT`).
70-
2. Push commit and tag.
137+
| Secret | Value |
138+
|--------|-------|
139+
| `CENTRAL_TOKEN_USERNAME` | Portal user token username |
140+
| `CENTRAL_TOKEN_PASSWORD` | Portal user token password |
141+
| `GPG_PRIVATE_KEY` | Output of `gpg --armor --export-secret-keys <KEY_ID>` |
142+
| `GPG_PASSPHRASE` | GPG key passphrase |
143+
144+
Then in your workflow:
145+
146+
```yaml
147+
- name: Import GPG key
148+
run: echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import
149+
150+
- name: Publish to Maven Central
151+
run: mvn -Prelease -DskipTests -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy
152+
env:
153+
CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
154+
CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
155+
```

danube-client-proto/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66

77
<parent>
8-
<groupId>com.danubemessaging</groupId>
8+
<groupId>com.danube-messaging</groupId>
99
<artifactId>danube-java</artifactId>
1010
<version>0.2.0</version>
1111
<relativePath>../pom.xml</relativePath>

danube-client/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66

77
<parent>
8-
<groupId>com.danubemessaging</groupId>
8+
<groupId>com.danube-messaging</groupId>
99
<artifactId>danube-java</artifactId>
1010
<version>0.2.0</version>
1111
<relativePath>../pom.xml</relativePath>
@@ -17,7 +17,7 @@
1717

1818
<dependencies>
1919
<dependency>
20-
<groupId>com.danubemessaging</groupId>
20+
<groupId>com.danube-messaging</groupId>
2121
<artifactId>danube-client-proto</artifactId>
2222
<version>${project.version}</version>
2323
</dependency>

danube-client/src/main/java/com/danubemessaging/client/Consumer.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@
1818
import java.util.concurrent.atomic.AtomicReference;
1919

2020
/**
21-
* Receives messages from a Danube topic and manages per-partition consumers.
21+
* Receives messages from a Danube topic.
22+
*
23+
* <p>Obtain an instance via {@link DanubeClient#newConsumer()}. Call {@link #subscribe()} to
24+
* register with the broker, then call {@link #receive()} to get the message stream.
25+
* Acknowledge each message with {@link #ack(StreamMessage)} to advance the subscription cursor.
26+
*
27+
* <p>This class is thread-safe.
2228
*/
2329
public final class Consumer implements AutoCloseable {
2430
private enum LifecycleState {
@@ -42,14 +48,32 @@ private enum LifecycleState {
4248
this.options = Objects.requireNonNull(options, "options");
4349
}
4450

51+
/**
52+
* Returns the options this consumer was built with.
53+
*
54+
* @return the consumer options
55+
*/
4556
public ConsumerOptions options() {
4657
return options;
4758
}
4859

60+
/**
61+
* Subscribes to the topic asynchronously.
62+
* Equivalent to calling {@link #subscribe()} on the IO executor.
63+
*
64+
* @return a future that completes when the subscription is established
65+
*/
4966
public CompletableFuture<Void> subscribeAsync() {
5067
return CompletableFuture.runAsync(this::subscribe, client.ioExecutor());
5168
}
5269

70+
/**
71+
* Subscribes to the topic and starts the background receive loop.
72+
* Must be called before {@link #receive()}.
73+
* Idempotent — calling twice on an already-subscribed consumer is a no-op.
74+
*
75+
* @throws com.danubemessaging.client.errors.DanubeClientException if subscription fails
76+
*/
5377
public synchronized void subscribe() {
5478
ensureOpen();
5579

@@ -103,14 +127,35 @@ public synchronized void subscribe() {
103127
}
104128
}
105129

130+
/**
131+
* Returns a {@link Flow.Publisher} that emits incoming {@link StreamMessage} objects.
132+
* Subscribe to this publisher with a {@link Flow.Subscriber} to process messages.
133+
* The publisher completes exceptionally if the receive loop encounters a fatal error.
134+
*
135+
* @return the message publisher for this consumer
136+
*/
106137
public Flow.Publisher<StreamMessage> receive() {
107138
return publisher;
108139
}
109140

141+
/**
142+
* Acknowledges a message asynchronously.
143+
*
144+
* @param message the message to acknowledge
145+
* @return a future that completes when the ack is sent
146+
*/
110147
public CompletableFuture<Void> ackAsync(StreamMessage message) {
111148
return CompletableFuture.runAsync(() -> ack(message), client.ioExecutor());
112149
}
113150

151+
/**
152+
* Acknowledges a message, advancing the subscription cursor past it.
153+
* Must be called for each message to prevent redelivery.
154+
*
155+
* @param message the message to acknowledge; must not be null
156+
* @throws com.danubemessaging.client.errors.DanubeClientException if the message's topic
157+
* has no associated consumer or the consumer is closed
158+
*/
114159
public void ack(StreamMessage message) {
115160
ensureOpen();
116161

@@ -128,6 +173,10 @@ public void ack(StreamMessage message) {
128173
notifyMessageAcked(topicConsumer, message);
129174
}
130175

176+
/**
177+
* Closes this consumer, cancels the receive loop, and releases all resources.
178+
* Idempotent — safe to call multiple times.
179+
*/
131180
@Override
132181
public synchronized void close() {
133182
if (lifecycleState.get() == LifecycleState.CLOSED) {

0 commit comments

Comments
 (0)