• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nats-io / nats.java / #2208

24 Sep 2025 01:14PM UTC coverage: 95.642% (+0.6%) from 95.051%
#2208

push

github

web-flow
Merge pull request #1403 from nats-io/2_12

(2.12) All 2.12 PRs combined

91 of 93 new or added lines in 9 files covered. (97.85%)

12091 of 12642 relevant lines covered (95.64%)

0.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.44
/src/main/java/io/nats/client/api/StreamConfiguration.java
1
// Copyright 2020 The NATS Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at:
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
package io.nats.client.api;
15

16
import io.nats.client.support.*;
17
import org.jspecify.annotations.NonNull;
18
import org.jspecify.annotations.Nullable;
19

20
import java.time.Duration;
21
import java.util.*;
22

23
import static io.nats.client.support.ApiConstants.*;
24
import static io.nats.client.support.JsonUtils.*;
25
import static io.nats.client.support.JsonValueUtils.*;
26
import static io.nats.client.support.JsonValueUtils.readBoolean;
27
import static io.nats.client.support.JsonValueUtils.readInteger;
28
import static io.nats.client.support.JsonValueUtils.readLong;
29
import static io.nats.client.support.JsonValueUtils.readNanos;
30
import static io.nats.client.support.JsonValueUtils.readString;
31
import static io.nats.client.support.Validator.*;
32

33
/**
34
 * The StreamConfiguration class specifies the configuration for creating a JetStream stream on the server.
35
 * Options are created using a {@link StreamConfiguration.Builder Builder}.
36
 */
37
public class StreamConfiguration implements JsonSerializable {
38

39
    // see builder for defaults
40
    private final String name;
41
    private final String description;
42
    private final List<String> subjects;
43
    private final RetentionPolicy retentionPolicy;
44
    private final CompressionOption compressionOption;
45
    private final long maxConsumers;
46
    private final long maxMsgs;
47
    private final long maxMsgsPerSubject;
48
    private final long maxBytes;
49
    private final Duration maxAge;
50
    private final int maxMsgSize;
51
    private final StorageType storageType;
52
    private final int replicas;
53
    private final boolean noAck;
54
    private final String templateOwner;
55
    private final DiscardPolicy discardPolicy;
56
    private final Duration duplicateWindow;
57
    private final Placement placement;
58
    private final Republish republish;
59
    private final SubjectTransform subjectTransform;
60
    private final ConsumerLimits consumerLimits;
61
    private final Mirror mirror;
62
    private final List<Source> sources;
63
    private final boolean sealed;
64
    private final boolean allowRollup;
65
    private final boolean allowDirect;
66
    private final boolean mirrorDirect;
67
    private final boolean denyDelete;
68
    private final boolean denyPurge;
69
    private final boolean discardNewPerSubject;
70
    private final Map<String, String> metadata;
71
    private final long firstSequence;
72
    private final Duration subjectDeleteMarkerTtl;
73
    private final boolean allowMessageTtl;
74
    private final boolean allowMsgSchedules;
75
    private final boolean allowMessageCounter;
76
    private final boolean allowAtomicPublish;
77

78
    static StreamConfiguration instance(JsonValue v) {
79
        return new Builder()
1✔
80
            .retentionPolicy(RetentionPolicy.get(readString(v, RETENTION)))
1✔
81
            .compressionOption(CompressionOption.get(readString(v, COMPRESSION)))
1✔
82
            .storageType(StorageType.get(readString(v, STORAGE)))
1✔
83
            .discardPolicy(DiscardPolicy.get(readString(v, DISCARD)))
1✔
84
            .name(readString(v, NAME))
1✔
85
            .description(readString(v, DESCRIPTION))
1✔
86
            .maxConsumers(readLong(v, MAX_CONSUMERS, -1))
1✔
87
            .maxMessages(readLong(v, MAX_MSGS, -1))
1✔
88
            .maxMessagesPerSubject(readLong(v, MAX_MSGS_PER_SUB, -1))
1✔
89
            .maxBytes(readLong(v, MAX_BYTES, -1))
1✔
90
            .maxAge(readNanos(v, MAX_AGE))
1✔
91
            .maximumMessageSize(readInteger(v, MAX_MSG_SIZE, -1))
1✔
92
            .replicas(readInteger(v, NUM_REPLICAS, 1))
1✔
93
            .noAck(readBoolean(v, NO_ACK))
1✔
94
            .templateOwner(readString(v, TEMPLATE_OWNER))
1✔
95
            .duplicateWindow(readNanos(v, DUPLICATE_WINDOW))
1✔
96
            .subjects(readStringList(v, SUBJECTS))
1✔
97
            .placement(Placement.optionalInstance(readValue(v, PLACEMENT)))
1✔
98
            .republish(Republish.optionalInstance(readValue(v, REPUBLISH)))
1✔
99
            .subjectTransform(SubjectTransform.optionalInstance(readValue(v, SUBJECT_TRANSFORM)))
1✔
100
            .consumerLimits(ConsumerLimits.optionalInstance(readValue(v, CONSUMER_LIMITS)))
1✔
101
            .mirror(Mirror.optionalInstance(readValue(v, MIRROR)))
1✔
102
            .sources(Source.optionalListOf(readValue(v, SOURCES)))
1✔
103
            .sealed(readBoolean(v, SEALED))
1✔
104
            .allowRollup(readBoolean(v, ALLOW_ROLLUP_HDRS))
1✔
105
            .allowDirect(readBoolean(v, ALLOW_DIRECT))
1✔
106
            .mirrorDirect(readBoolean(v, MIRROR_DIRECT))
1✔
107
            .denyDelete(readBoolean(v, DENY_DELETE))
1✔
108
            .denyPurge(readBoolean(v, DENY_PURGE))
1✔
109
            .discardNewPerSubject(readBoolean(v, DISCARD_NEW_PER_SUBJECT))
1✔
110
            .metadata(readStringStringMap(v, METADATA))
1✔
111
            .firstSequence(readLong(v, FIRST_SEQ, 1))
1✔
112
            .subjectDeleteMarkerTtl(readNanos(v, SUBJECT_DELETE_MARKER_TTL))
1✔
113
            .allowMessageTtl(readBoolean(v, ALLOW_MSG_TTL))
1✔
114
            .allowMessageSchedules(readBoolean(v, ALLOW_MSG_SCHEDULES))
1✔
115
            .allowMessageCounter(readBoolean(v, ALLOW_MSG_COUNTER))
1✔
116
            .allowAtomicPublish(readBoolean(v, ALLOW_ATOMIC))
1✔
117
            .build();
1✔
118
    }
119

120
    // For the builder, assumes all validations are already done in builder
121
    StreamConfiguration(Builder b) {
1✔
122
        this.name = b.name;
1✔
123
        this.description = b.description;
1✔
124
        this.subjects = b.subjects;
1✔
125
        this.retentionPolicy = b.retentionPolicy;
1✔
126
        this.compressionOption = b.compressionOption;
1✔
127
        this.maxConsumers = b.maxConsumers;
1✔
128
        this.maxMsgs = b.maxMsgs;
1✔
129
        this.maxMsgsPerSubject = b.maxMsgsPerSubject;
1✔
130
        this.maxBytes = b.maxBytes;
1✔
131
        this.maxAge = b.maxAge;
1✔
132
        this.maxMsgSize = b.maxMsgSize;
1✔
133
        this.storageType = b.storageType;
1✔
134
        this.replicas = b.replicas;
1✔
135
        this.noAck = b.noAck;
1✔
136
        this.templateOwner = b.templateOwner;
1✔
137
        this.discardPolicy = b.discardPolicy;
1✔
138
        this.duplicateWindow = b.duplicateWindow;
1✔
139
        this.placement = b.placement;
1✔
140
        this.republish = b.republish;
1✔
141
        this.subjectTransform = b.subjectTransform;
1✔
142
        this.consumerLimits = b.consumerLimits;
1✔
143
        this.mirror = b.mirror;
1✔
144
        this.sources = b.sources;
1✔
145
        this.sealed = b.sealed;
1✔
146
        this.allowRollup = b.allowRollup;
1✔
147
        this.allowDirect = b.allowDirect;
1✔
148
        this.mirrorDirect = b.mirrorDirect;
1✔
149
        this.denyDelete = b.denyDelete;
1✔
150
        this.denyPurge = b.denyPurge;
1✔
151
        this.discardNewPerSubject = b.discardNewPerSubject;
1✔
152
        this.metadata = b.metadata;
1✔
153
        this.firstSequence = b.firstSequence;
1✔
154
        this.subjectDeleteMarkerTtl = b.subjectDeleteMarkerTtl;
1✔
155
        this.allowMessageTtl = b.allowMessageTtl;
1✔
156
        this.allowMsgSchedules = b.allowMsgSchedules;
1✔
157
        this.allowMessageCounter = b.allowMessageCounter;
1✔
158
        this.allowAtomicPublish = b.allowAtomicPublish;
1✔
159
    }
1✔
160

161
    /**
162
     * Returns a StreamConfiguration deserialized from its JSON form.
163
     *
164
     * @see #toJson()
165
     * @param json the json representing the Stream Configuration
166
     * @return StreamConfiguration for the given json
167
     * @throws JsonParseException thrown if the parsing fails for invalid json
168
     */
169
    public static StreamConfiguration instance(String json) throws JsonParseException {
170
        return instance(JsonParser.parse(json));
1✔
171
    }
172

173
    /**
174
     * Returns a JSON representation of this consumer configuration.
175
     *
176
     * @return json consumer configuration to send to the server.
177
     */
178
    @Override
179
    @NonNull
180
    public String toJson() {
181

182
        StringBuilder sb = beginJson();
1✔
183

184
        addField(sb, NAME, name);
1✔
185
        JsonUtils.addField(sb, DESCRIPTION, description);
1✔
186
        addStrings(sb, SUBJECTS, subjects);
1✔
187
        addField(sb, RETENTION, retentionPolicy.toString());
1✔
188
        addEnumWhenNot(sb, COMPRESSION, compressionOption, CompressionOption.None);
1✔
189
        addField(sb, MAX_CONSUMERS, maxConsumers);
1✔
190
        addField(sb, MAX_MSGS, maxMsgs);
1✔
191
        addField(sb, MAX_MSGS_PER_SUB, maxMsgsPerSubject);
1✔
192
        addField(sb, MAX_BYTES, maxBytes);
1✔
193
        addFieldAsNanos(sb, MAX_AGE, maxAge);
1✔
194
        addField(sb, MAX_MSG_SIZE, maxMsgSize);
1✔
195
        addField(sb, STORAGE, storageType.toString());
1✔
196
        addField(sb, NUM_REPLICAS, replicas);
1✔
197
        addFldWhenTrue(sb, NO_ACK, noAck);
1✔
198
        addField(sb, TEMPLATE_OWNER, templateOwner);
1✔
199
        addField(sb, DISCARD, discardPolicy.toString());
1✔
200
        addFieldAsNanos(sb, DUPLICATE_WINDOW, duplicateWindow);
1✔
201
        if (placement != null && placement.hasData()) {
1✔
202
            addField(sb, PLACEMENT, placement);
1✔
203
        }
204
        addField(sb, REPUBLISH, republish);
1✔
205
        addField(sb, SUBJECT_TRANSFORM, subjectTransform);
1✔
206
        addField(sb, CONSUMER_LIMITS, consumerLimits);
1✔
207
        addField(sb, MIRROR, mirror);
1✔
208
        addJsons(sb, SOURCES, sources);
1✔
209
        addFldWhenTrue(sb, SEALED, sealed);
1✔
210
        addFldWhenTrue(sb, ALLOW_ROLLUP_HDRS, allowRollup);
1✔
211
        addFldWhenTrue(sb, ALLOW_DIRECT, allowDirect);
1✔
212
        addFldWhenTrue(sb, MIRROR_DIRECT, mirrorDirect);
1✔
213
        addFldWhenTrue(sb, DENY_DELETE, denyDelete);
1✔
214
        addFldWhenTrue(sb, DENY_PURGE, denyPurge);
1✔
215
        addFldWhenTrue(sb, DISCARD_NEW_PER_SUBJECT, discardNewPerSubject);
1✔
216
        addField(sb, METADATA, metadata);
1✔
217
        addFieldWhenGreaterThan(sb, FIRST_SEQ, firstSequence, 1);
1✔
218
        addFieldAsNanos(sb, SUBJECT_DELETE_MARKER_TTL, subjectDeleteMarkerTtl);
1✔
219
        addFldWhenTrue(sb, ALLOW_MSG_TTL, allowMessageTtl);
1✔
220
        addFldWhenTrue(sb, ALLOW_MSG_SCHEDULES, allowMsgSchedules);
1✔
221
        addFldWhenTrue(sb, ALLOW_MSG_COUNTER, allowMessageCounter);
1✔
222
        addFldWhenTrue(sb, ALLOW_ATOMIC, allowAtomicPublish);
1✔
223

224
        return endJson(sb).toString();
1✔
225
    }
226

227
    /**
228
     * Gets the name of this stream configuration.
229
     * @return the name of the stream.
230
     */
231
    @NonNull
232
    public String getName() {
233
        return name;
1✔
234
    }
235

236
    /**
237
     * Gets the description of this stream configuration.
238
     * @return the description of the stream.
239
     */
240
    @Nullable
241
    public String getDescription() {
242
        return description;
1✔
243
    }
244

245
    /**
246
     * Gets the subjects for this stream configuration.
247
     * @return the subject of the stream.
248
     */
249
    @NonNull
250
    public List<String> getSubjects() {
251
        return subjects;
1✔
252
    }
253

254
    /**
255
     * Gets the discard policy for this stream configuration.
256
     * @return the discard policy of the stream.
257
     */
258
    @Nullable
259
    public DiscardPolicy getDiscardPolicy() {
260
        return discardPolicy;
1✔
261
    }
262

263
    /**
264
     * Gets the retention policy for this stream configuration.
265
     * @return the retention policy for this stream.
266
     */
267
    @NonNull
268
    public RetentionPolicy getRetentionPolicy() {
269
        return retentionPolicy;
1✔
270
    }
271

272
    /**
273
     * Gets the compression option for this stream configuration.
274
     * @return the compression option for this stream.
275
     */
276
    @Nullable
277
    public CompressionOption getCompressionOption() {
278
        return compressionOption;
1✔
279
    }
280

281
    /**
282
     * Gets the maximum number of consumers for this stream configuration.
283
     * @return the maximum number of consumers for this stream.
284
     */
285
    public long getMaxConsumers() {
286
        return maxConsumers;
1✔
287
    }
288

289
    /**
290
     * Gets the maximum messages for this stream configuration.
291
     * @return the maximum number of messages for this stream.
292
     */
293
    public long getMaxMsgs() {
294
        return maxMsgs;
1✔
295
    }
296

297
    /**
298
     * Gets the maximum messages for this stream configuration.
299
     * @return the maximum number of messages for this stream.
300
     */
301
    public long getMaxMsgsPerSubject() {
302
        return maxMsgsPerSubject;
1✔
303
    }
304

305
    /**
306
     * Gets the maximum number of bytes for this stream configuration.
307
     * @return the maximum number of bytes for this stream.
308
     */
309
    public long getMaxBytes() {
310
        return maxBytes;
1✔
311
    }
312

313
    /**
314
     * Gets the maximum message age for this stream configuration.
315
     * @return the maximum message age for this stream.
316
     */
317
    @NonNull
318
    public Duration getMaxAge() {
319
        return maxAge;
1✔
320
    }
321

322
    /**
323
     * Gets the maximum message size for this stream configuration.
324
     * @deprecated the server value is a 32-bit signed value. Use {@link #getMaximumMessageSize()} instead.
325
     * @return the maximum message size for this stream.
326
     */
327
    @Deprecated
328
    public long getMaxMsgSize() {
329
        return maxMsgSize;
1✔
330
    }
331

332
    /**
333
     * Gets the maximum message size for this stream configuration.
334
     * @return the maximum message size for this stream.
335
     */
336
    public int getMaximumMessageSize() {
337
        return maxMsgSize;
1✔
338
    }
339

340
    /**
341
     * Gets the storage type for this stream configuration.
342
     * @return the storage type for this stream.
343
     */
344
    @NonNull
345
    public StorageType getStorageType() {
346
        return storageType;
1✔
347
    }
348

349
    /**
350
     * Gets the number of replicas for this stream configuration.
351
     * @return the number of replicas
352
     */    
353
    public int getReplicas() {
354
        return replicas;
1✔
355
    }
356

357
    /**
358
     * Gets whether acknowledgements are required in this stream configuration.
359
     * @return true if acknowedgments are not required.
360
     */
361
    public boolean getNoAck() {
362
        return noAck;
1✔
363
    }
364

365
    /**
366
     * Gets the template json for this stream configuration.
367
     * @return the template for this stream.
368
     */
369
    @Nullable
370
    public String getTemplateOwner() {
371
        return templateOwner;
1✔
372
    }
373

374
    /**
375
     * Gets the duplicate checking window stream configuration.  Duration.ZERO
376
     * means duplicate checking is not enabled.
377
     * @return the duration of the window.
378
     */
379
    @Nullable
380
    public Duration getDuplicateWindow() {
381
        return duplicateWindow;
1✔
382
    }
383

384
    /**
385
     * Get the placement directives to consider when placing replicas of this stream,
386
     * random placement when unset. May be null.
387
     * @return the placement object
388
     */
389
    @Nullable
390
    public Placement getPlacement() {
391
        return placement;
1✔
392
    }
393

394
    /**
395
     * Get the republish configuration. May be null.
396
     * @return the republish object
397
     */
398
    @Nullable
399
    public Republish getRepublish() {
400
        return republish;
1✔
401
    }
402

403
    /**
404
     * Get the subjectTransform configuration. May be null.
405
     * @return the subjectTransform object
406
     */
407
    @Nullable
408
    public SubjectTransform getSubjectTransform() {
409
        return subjectTransform;
1✔
410
    }
411

412
    /**
413
     * Get the consumerLimits configuration. May be null.
414
     * @return the consumerLimits object
415
     */
416
    @Nullable
417
    public ConsumerLimits getConsumerLimits() {
418
        return consumerLimits;
1✔
419
    }
420

421
    /**
422
     * The mirror definition for this stream
423
     * @return the mirror
424
     */
425
    @Nullable
426
    public Mirror getMirror() {
427
        return mirror;
1✔
428
    }
429

430
    /**
431
     * The sources for this stream
432
     * @return the sources
433
     */
434
    @Nullable
435
    public List<Source> getSources() {
436
        return sources;
1✔
437
    }
438

439
    /**
440
     * Get the flag indicating if the stream is sealed.
441
     * @return the sealed flag
442
     */
443
    public boolean getSealed() {
444
        return sealed;
1✔
445
    }
446

447
    /**
448
     * Get the flag indicating if the stream allows rollup.
449
     * @return the allows rollup flag
450
     */
451
    public boolean getAllowRollup() {
452
        return allowRollup;
1✔
453
    }
454

455
    /**
456
     * Get the flag indicating if the stream allows direct message access.
457
     * @return the allows direct flag
458
     */
459
    public boolean getAllowDirect() {
460
        return allowDirect;
1✔
461
    }
462

463
    /**
464
     * Get the flag indicating if the stream allows
465
     * higher performance and unified direct access for mirrors as well.
466
     * @return the allows direct flag
467
     */
468
    public boolean getMirrorDirect() {
469
        return mirrorDirect;
1✔
470
    }
471

472
    /**
473
     * Get the flag indicating if deny delete is set for the stream
474
     * @return the deny delete flag
475
     */
476
    public boolean getDenyDelete() {
477
        return denyDelete;
1✔
478
    }
479

480
    /**
481
     * Get the flag indicating if deny purge is set for the stream
482
     * @return the deny purge flag
483
     */
484
    public boolean getDenyPurge() {
485
        return denyPurge;
1✔
486
    }
487

488
    /**
489
     * Whether discard policy with max message per subject is applied per subject.
490
     * @return the discard new per subject flag
491
     */
492
    public boolean isDiscardNewPerSubject() {
493
        return discardNewPerSubject;
1✔
494
    }
495

496
    /**
497
     * Metadata for the stream
498
     * @return the metadata map. Might be null.
499
     */
500
    @Nullable
501
    public Map<String, String> getMetadata() {
502
        return metadata;
1✔
503
    }
504

505
    /**
506
     * The first sequence used in the stream.
507
     * @return the first sequence
508
     */
509
    public long getFirstSequence() {
510
        return firstSequence;
1✔
511
    }
512

513
    /**
514
     * @deprecated Prefer getAllowMessageTtl
515
     * Whether Allow Message TTL is set
516
     * @return the flag
517
     */
518
    @Deprecated
519
    public boolean isAllowMessageTtl() {
520
        return allowMessageTtl;
1✔
521
    }
522

523
    /**
524
     * Whether Allow Message TTL is set
525
     * @return the flag
526
     */
527
    public boolean getAllowMessageTtl() {
528
        return allowMessageTtl;
1✔
529
    }
530

531
    /**
532
     * Whether Allow Message Schedules is set
533
     * @return the flag
534
     */
535
    public boolean getAllowMsgSchedules() {
536
        return allowMsgSchedules;
1✔
537
    }
538

539
    /**
540
     * Whether Allow Message Counter is set
541
     * @return the flag
542
     */
543
    public boolean getAllowMessageCounter() {
544
        return allowMessageCounter;
1✔
545
    }
546

547
    /**
548
     * Whether Allow Atomic Publish is set
549
     * @return the flag
550
     */
551
    public boolean getAllowAtomicPublish() {
552
        return allowAtomicPublish;
1✔
553
    }
554

555
    /**
556
     * Get the Subject Delete Marker TTL duration. May be null.
557
     * @return The duration
558
     */
559
    @Nullable
560
    public Duration getSubjectDeleteMarkerTtl() {
561
        return subjectDeleteMarkerTtl;
1✔
562
    }
563

564
    @Override
565
    public String toString() {
566
        return toJson();
1✔
567
    }
568

569
    /**
570
     * Creates a builder for the stream configuration.
571
     * @return a stream configuration builder
572
     */
573
    public static Builder builder() {
574
        return new Builder();
1✔
575
    }
576

577
    /**
578
     * Creates a builder to copy the stream configuration.
579
     * @param sc an existing StreamConfiguration
580
     * @return a stream configuration builder
581
     */
582
    public static Builder builder(StreamConfiguration sc) {
583
        return new Builder(sc);
1✔
584
    }
585

586
    /**
587
     * StreamConfiguration is created using a Builder. The builder supports chaining and will
588
     * create a default set of options if no methods are calls.
589
     * 
590
     * <p>{@code new StreamConfiguration.Builder().build()} will create a new StreamConfiguration.
591
     * 
592
     */
593
    public static class Builder {
594

595
        private String name = null;
1✔
596
        private String description = null;
1✔
597
        private final List<String> subjects = new ArrayList<>();
1✔
598
        private RetentionPolicy retentionPolicy = RetentionPolicy.Limits;
1✔
599
        private CompressionOption compressionOption = CompressionOption.None;
1✔
600
        private long maxConsumers = -1;
1✔
601
        private long maxMsgs = -1;
1✔
602
        private long maxMsgsPerSubject = -1;
1✔
603
        private long maxBytes = -1;
1✔
604
        private Duration maxAge = Duration.ZERO;
1✔
605
        private int maxMsgSize = -1;
1✔
606
        private StorageType storageType = StorageType.File;
1✔
607
        private int replicas = 1;
1✔
608
        private boolean noAck = false;
1✔
609
        private String templateOwner = null;
1✔
610
        private DiscardPolicy discardPolicy = DiscardPolicy.Old;
1✔
611
        private Duration duplicateWindow = Duration.ZERO;
1✔
612
        private Placement placement = null;
1✔
613
        private Republish republish = null;
1✔
614
        private SubjectTransform subjectTransform = null;
1✔
615
        private ConsumerLimits consumerLimits = null;
1✔
616
        private Mirror mirror = null;
1✔
617
        private final List<Source> sources = new ArrayList<>();
1✔
618
        private boolean sealed = false;
1✔
619
        private boolean allowRollup = false;
1✔
620
        private boolean allowDirect = false;
1✔
621
        private boolean mirrorDirect = false;
1✔
622
        private boolean denyDelete = false;
1✔
623
        private boolean denyPurge = false;
1✔
624
        private boolean discardNewPerSubject = false;
1✔
625
        private Map<String, String> metadata;
626
        private long firstSequence = 1;
1✔
627
        private Duration subjectDeleteMarkerTtl;
628
        private boolean allowMessageTtl = false;
1✔
629
        private boolean allowMsgSchedules = false;
1✔
630
        private boolean allowMessageCounter = false;
1✔
631
        private boolean allowAtomicPublish = false;
1✔
632

633
        /**
634
         * Default Builder
635
         */
636
        public Builder() {}
1✔
637

638
        /**
639
         * Update Builder, useful if you need to update a configuration
640
         * @param sc the configuration to copy
641
         */
642
        public Builder(StreamConfiguration sc) {
1✔
643
            if (sc != null) {
1✔
644
                this.name = sc.name;
1✔
645
                this.description = sc.description;
1✔
646
                subjects(sc.subjects);
1✔
647
                this.retentionPolicy = sc.retentionPolicy;
1✔
648
                this.compressionOption = sc.compressionOption;
1✔
649
                this.maxConsumers = sc.maxConsumers;
1✔
650
                this.maxMsgs = sc.maxMsgs;
1✔
651
                this.maxMsgsPerSubject = sc.maxMsgsPerSubject;
1✔
652
                this.maxBytes = sc.maxBytes;
1✔
653
                this.maxAge = sc.maxAge;
1✔
654
                this.maxMsgSize = sc.maxMsgSize;
1✔
655
                this.storageType = sc.storageType;
1✔
656
                this.replicas = sc.replicas;
1✔
657
                this.noAck = sc.noAck;
1✔
658
                this.templateOwner = sc.templateOwner;
1✔
659
                this.discardPolicy = sc.discardPolicy;
1✔
660
                this.duplicateWindow = sc.duplicateWindow;
1✔
661
                this.placement = sc.placement;
1✔
662
                this.republish = sc.republish;
1✔
663
                this.subjectTransform = sc.subjectTransform;
1✔
664
                this.consumerLimits = sc.consumerLimits;
1✔
665
                this.mirror = sc.mirror;
1✔
666
                sources(sc.sources);
1✔
667
                this.sealed = sc.sealed;
1✔
668
                this.allowRollup = sc.allowRollup;
1✔
669
                this.allowDirect = sc.allowDirect;
1✔
670
                this.mirrorDirect = sc.mirrorDirect;
1✔
671
                this.denyDelete = sc.denyDelete;
1✔
672
                this.denyPurge = sc.denyPurge;
1✔
673
                this.discardNewPerSubject = sc.discardNewPerSubject;
1✔
674
                if (sc.metadata != null) {
1✔
675
                    this.metadata = new HashMap<>(sc.metadata);
1✔
676
                }
677
                this.firstSequence = sc.firstSequence;
1✔
678
                this.subjectDeleteMarkerTtl = sc.subjectDeleteMarkerTtl;
1✔
679
                this.allowMessageTtl = sc.allowMessageTtl;
1✔
680
                this.allowMsgSchedules = sc.allowMsgSchedules;
1✔
681
                this.allowMessageCounter = sc.allowMessageCounter;
1✔
682
                this.allowAtomicPublish = sc.allowAtomicPublish;
1✔
683
            }
684
        }
1✔
685

686
        /**
687
         * Sets the name of the stream.
688
         * @param name name of the stream.
689
         * @return the builder
690
         */
691
        public Builder name(String name) {
692
            this.name =  validateStreamName(name, false);
1✔
693
            return this;
1✔
694
        }
695

696
        /**
697
         * Sets the description
698
         * @param description the description
699
         * @return the builder
700
         */
701
        public Builder description(String description) {
702
            this.description = description;
1✔
703
            return this;
1✔
704
        }
705

706
        /**
707
         * Sets the subjects in the StreamConfiguration.
708
         * @param subjects the stream's subjects
709
         * @return The Builder
710
         */
711
        public Builder subjects(String... subjects) {
712
            this.subjects.clear();
1✔
713
            return addSubjects(subjects);
1✔
714
        }
715

716
        /**
717
         * Sets the subjects in the StreamConfiguration.
718
         * @param subjects the stream's subjects
719
         * @return The Builder
720
         */
721
        public Builder subjects(Collection<String> subjects) {
722
            this.subjects.clear();
1✔
723
            return addSubjects(subjects);
1✔
724
        }
725

726
        /**
727
         * Adds unique subjects into the StreamConfiguration.
728
         * @param subjects the stream's subjects to add
729
         * @return The Builder
730
         */
731
        public Builder addSubjects(String... subjects) {
732
            if (subjects != null) {
1✔
733
                return addSubjects(Arrays.asList(subjects));
1✔
734
            }
735
            return this;
1✔
736
        }
737

738
        /**
739
         * Adds unique subjects into the StreamConfiguration.
740
         * @param subjects the stream's subjects to add
741
         * @return The Builder
742
         */
743
        public Builder addSubjects(Collection<String> subjects) {
744
            if (subjects != null) {
1✔
745
                for (String sub : subjects) {
1✔
746
                    if (sub != null && !this.subjects.contains(sub)) {
1✔
747
                        this.subjects.add(sub);
1✔
748
                    }
749
                }
1✔
750
            }
751
            return this;
1✔
752
        }
753

754
        /**
755
         * Sets the retention policy in the StreamConfiguration.
756
         * @param policy the retention policy of the StreamConfiguration
757
         * @return The Builder
758
         */
759
        public Builder retentionPolicy(RetentionPolicy policy) {
760
            this.retentionPolicy = policy == null ? RetentionPolicy.Limits : policy;
1✔
761
            return this;
1✔
762
        }
763

764
        /**
765
         * Sets the compression option in the StreamConfiguration.
766
         * @param compressionOption the compression option of the StreamConfiguration
767
         * @return The Builder
768
         */
769
        public Builder compressionOption(CompressionOption compressionOption) {
770
            this.compressionOption = compressionOption == null ? CompressionOption.None : compressionOption;
1✔
771
            return this;
1✔
772
        }
773

774
        /**
775
         * Sets the maximum number of consumers in the StreamConfiguration.
776
         * @param maxConsumers the maximum number of consumers
777
         * @return The Builder
778
         */        
779
        public Builder maxConsumers(long maxConsumers) {
780
            this.maxConsumers = validateMaxConsumers(maxConsumers);
1✔
781
            return this;
1✔
782
        }
783

784
        /**
785
         * Sets the maximum number of messages in the StreamConfiguration.
786
         * @param maxMsgs the maximum number of messages
787
         * @return The Builder
788
         */
789
        public Builder maxMessages(long maxMsgs) {
790
            this.maxMsgs = validateMaxMessages(maxMsgs);
1✔
791
            return this;
1✔
792
        }
793

794
        /**
795
         * Sets the maximum number of message per subject in the StreamConfiguration.
796
         * @param maxMsgsPerSubject the maximum number of messages
797
         * @return The Builder
798
         */
799
        public Builder maxMessagesPerSubject(long maxMsgsPerSubject) {
800
            this.maxMsgsPerSubject = validateMaxMessagesPerSubject(maxMsgsPerSubject);
1✔
801
            return this;
1✔
802
        }
803

804
        /**
805
         * Sets the maximum number of bytes in the StreamConfiguration.
806
         * @param maxBytes the maximum number of bytes
807
         * @return The Builder
808
         */
809
        public Builder maxBytes(long maxBytes) {
810
            this.maxBytes = validateMaxBytes(maxBytes);
1✔
811
            return this;
1✔
812
        }
813

814
        /**
815
         * Sets the maximum age in the StreamConfiguration.
816
         * @param maxAge the maximum message age
817
         * @return The Builder
818
         */
819
        public Builder maxAge(Duration maxAge) {
820
            this.maxAge = validateDurationNotRequiredGtOrEqZero(maxAge, Duration.ZERO);
1✔
821
            return this;
1✔
822
        }
823

824
        /**
825
         * Sets the maximum age in the StreamConfiguration.
826
         * @param maxAgeMillis the maximum message age
827
         * @return The Builder
828
         */
829
        public Builder maxAge(long maxAgeMillis) {
830
            this.maxAge = validateDurationNotRequiredGtOrEqZero(maxAgeMillis);
1✔
831
            return this;
1✔
832
        }
833

834
        /**
835
         * Sets the maximum message size in the StreamConfiguration.
836
         * @deprecated the server value is a 32-bit signed value. Use {@link #maximumMessageSize(int)} instead.
837
         * @param maxMsgSize the maximum message size
838
         * @return The Builder
839
         */
840
        @Deprecated
841
        public Builder maxMsgSize(long maxMsgSize) {
842
            this.maxMsgSize = (int)validateMaxMessageSize(maxMsgSize);
1✔
843
            return this;
1✔
844
        }
845

846
        /**
847
         * Sets the maximum message size in the StreamConfiguration.
848
         * @param maxMsgSize the maximum message size
849
         * @return The Builder
850
         */
851
        public Builder maximumMessageSize(int maxMsgSize) {
852
            this.maxMsgSize = (int)validateMaxMessageSize(maxMsgSize);
1✔
853
            return this;
1✔
854
        }
855

856
        /**
857
         * Sets the storage type in the StreamConfiguration.
858
         * @param storageType the storage type
859
         * @return The Builder
860
         */        
861
        public Builder storageType(StorageType storageType) {
862
            this.storageType = storageType == null ? StorageType.File : storageType;
1✔
863
            return this;
1✔
864
        }
865

866
        /**
867
         * Sets the number of replicas a message must be stored on in the StreamConfiguration.
868
         * Must be 1 to 5 inclusive
869
         * @param replicas the number of replicas to store this message on
870
         * @return The Builder
871
         */
872
        public Builder replicas(int replicas) {
873
            this.replicas = validateNumberOfReplicas(replicas);
1✔
874
            return this;
1✔
875
        }
876

877
        /**
878
         * Sets the acknowledgement mode of the StreamConfiguration.  if no acknowledgements are
879
         * set, then acknowledgements are not sent back to the client.  The default is false.
880
         * @param noAck true to disable acknowledgements.
881
         * @return The Builder
882
         */        
883
        public Builder noAck(boolean noAck) {
884
            this.noAck = noAck;
1✔
885
            return this;
1✔
886
        }
887

888
        /**
889
         * Sets the template a stream in the form of raw JSON.
890
         * @param templateOwner the stream template of the stream.
891
         * @return the builder
892
         */
893
        public Builder templateOwner(String templateOwner) {
894
            this.templateOwner = emptyAsNull(templateOwner);
1✔
895
            return this;
1✔
896
        }
897

898
        /**
899
         * Sets the discard policy in the StreamConfiguration.
900
         * @param policy the discard policy of the StreamConfiguration
901
         * @return The Builder
902
         */
903
        public Builder discardPolicy(DiscardPolicy policy) {
904
            this.discardPolicy = policy == null ? DiscardPolicy.Old : policy;
1✔
905
            return this;
1✔
906
        }
907

908
        /**
909
         * Sets the duplicate checking window in the StreamConfiguration.  A Duration.Zero
910
         * disables duplicate checking.  Duplicate checking is disabled by default.
911
         * @param window duration to hold message ids for duplicate checking.
912
         * @return The Builder
913
         */
914
        public Builder duplicateWindow(Duration window) {
915
            this.duplicateWindow = validateDurationNotRequiredGtOrEqZero(window, Duration.ZERO);
1✔
916
            return this;
1✔
917
        }
918

919
        /**
920
         * Sets the duplicate checking window in the StreamConfiguration.  A Duration.Zero
921
         * disables duplicate checking.  Duplicate checking is disabled by default.
922
         * @param windowMillis duration to hold message ids for duplicate checking.
923
         * @return The Builder
924
         */
925
        public Builder duplicateWindow(long windowMillis) {
926
            this.duplicateWindow = validateDurationNotRequiredGtOrEqZero(windowMillis);
1✔
927
            return this;
1✔
928
        }
929

930
        /**
931
         * Sets the placement directive object
932
         * @param placement the placement directive object
933
         * @return The Builder
934
         */
935
        public Builder placement(Placement placement) {
936
            this.placement = placement;
1✔
937
            return this;
1✔
938
        }
939

940
        /**
941
         * Sets the republish config object
942
         * @param republish the republish config object
943
         * @return The Builder
944
         */
945
        public Builder republish(Republish republish) {
946
            this.republish = republish;
1✔
947
            return this;
1✔
948
        }
949

950
        /**
951
         * Sets the subjectTransform config object
952
         * @param subjectTransform the subjectTransform config object
953
         * @return The Builder
954
         */
955
        public Builder subjectTransform(SubjectTransform subjectTransform) {
956
            this.subjectTransform = subjectTransform;
1✔
957
            return this;
1✔
958
        }
959

960
        /**
961
         * Sets the consumerLimits config object
962
         * @param consumerLimits the consumerLimits config object
963
         * @return The Builder
964
         */
965
        public Builder consumerLimits(ConsumerLimits consumerLimits) {
966
            this.consumerLimits = consumerLimits;
1✔
967
            return this;
1✔
968
        }
969

970
        /**
971
         * Sets the mirror  object
972
         * @param mirror the mirror object
973
         * @return The Builder
974
         */
975
        public Builder mirror(Mirror mirror) {
976
            this.mirror = mirror;
1✔
977
            return this;
1✔
978
        }
979

980
        /**
981
         * Sets the sources in the StreamConfiguration.
982
         * @param sources the stream's sources
983
         * @return The Builder
984
         */
985
        public Builder sources(Source... sources) {
986
            this.sources.clear();
1✔
987
            return addSources(sources);
1✔
988
        }
989

990
        /**
991
         * Add the sources into the StreamConfiguration.
992
         * @param sources the stream's sources
993
         * @return The Builder
994
         */
995
        public Builder sources(Collection<Source> sources) {
996
            this.sources.clear();
1✔
997
            return addSources(sources);
1✔
998
        }
999

1000
        /**
1001
         * Add the sources into the StreamConfiguration.
1002
         * @param sources the stream's sources
1003
         * @return The Builder
1004
         */
1005
        public Builder addSources(Source... sources) {
1006
            return addSources(Arrays.asList(sources));
1✔
1007
        }
1008

1009
        /**
1010
         * Sets the sources in the StreamConfiguration.
1011
         * @param sources the stream's sources
1012
         * @return The Builder
1013
         */
1014
        public Builder addSources(Collection<Source> sources) {
1015
            if (sources != null) {
1✔
1016
                for (Source source : sources) {
1✔
1017
                    if (source != null && !this.sources.contains(source)) {
1✔
1018
                        this.sources.add(source);
1✔
1019
                    }
1020
                }
1✔
1021
            }
1022
            return this;
1✔
1023
        }
1024

1025
        /**
1026
         * Add a source into the StreamConfiguration.
1027
         * @param source a stream source
1028
         * @return The Builder
1029
         */
1030
        public Builder addSource(Source source) {
1031
            if (source != null && !this.sources.contains(source)) {
1✔
1032
                this.sources.add(source);
1✔
1033
            }
1034
            return this;
1✔
1035
        }
1036

1037
        /**
1038
         * Set whether to seal the stream.
1039
         * INTERNAL USE ONLY. Scoped protected for test purposes.
1040
         * @param sealed the sealed setting
1041
         * @return The Builder
1042
         */
1043
        protected Builder sealed(boolean sealed) {
1044
            this.sealed = sealed;
1✔
1045
            return this;
1✔
1046
        }
1047

1048
        /**
1049
         * Set whether to allow the rollup feature for a stream
1050
         * @param allowRollup the allow rollup setting
1051
         * @return The Builder
1052
         */
1053
        public Builder allowRollup(boolean allowRollup) {
1054
            this.allowRollup = allowRollup;
1✔
1055
            return this;
1✔
1056
        }
1057

1058
        /**
1059
         * Set whether to allow direct message access for a stream
1060
         * @param allowDirect the allow direct setting
1061
         * @return The Builder
1062
         */
1063
        public Builder allowDirect(boolean allowDirect) {
1064
            this.allowDirect = allowDirect;
1✔
1065
            return this;
1✔
1066
        }
1067

1068
        /**
1069
         * Set whether to allow unified direct access for mirrors
1070
         * @param mirrorDirect the allow direct setting
1071
         * @return The Builder
1072
         */
1073
        public Builder mirrorDirect(boolean mirrorDirect) {
1074
            this.mirrorDirect = mirrorDirect;
1✔
1075
            return this;
1✔
1076
        }
1077

1078
        /**
1079
         * Set whether to deny deleting messages from the stream
1080
         * @param denyDelete the deny delete setting
1081
         * @return The Builder
1082
         */
1083
        public Builder denyDelete(boolean denyDelete) {
1084
            this.denyDelete = denyDelete;
1✔
1085
            return this;
1✔
1086
        }
1087

1088
        /**
1089
         * Set whether to deny purging messages from the stream
1090
         * @param denyPurge the deny purge setting
1091
         * @return The Builder
1092
         */
1093
        public Builder denyPurge(boolean denyPurge) {
1094
            this.denyPurge = denyPurge;
1✔
1095
            return this;
1✔
1096
        }
1097

1098
        /**
1099
         * Set whether discard policy new with max message per subject applies to existing subjects, not just new subjects.
1100
         * @param discardNewPerSubject the setting
1101
         * @return The Builder
1102
         */
1103
        public Builder discardNewPerSubject(boolean discardNewPerSubject) {
1104
            this.discardNewPerSubject = discardNewPerSubject;
1✔
1105
            return this;
1✔
1106
        }
1107

1108
        /**
1109
         * Set this stream to be sealed. This is irreversible.
1110
         * @return The Builder
1111
         */
1112
        public Builder seal() {
1113
            this.sealed = true;
1✔
1114
            return this;
1✔
1115
        }
1116

1117
        /**
1118
         * Sets the metadata for the configuration
1119
         * @param metadata the metadata map
1120
         * @return The Builder
1121
         */
1122
        public Builder metadata(Map<String, String> metadata) {
1123
            this.metadata = metadata;
1✔
1124
            return this;
1✔
1125
        }
1126

1127
        /**
1128
         * Sets the first sequence to be used. 1 is the default. All values less than 2 are treated as 1.
1129
         * @param firstSeq specify the first_seq in the stream config when creating the stream.
1130
         * @return The Builder
1131
         */
1132
        public Builder firstSequence(long firstSeq) {
1133
            this.firstSequence = firstSeq > 1 ? firstSeq : 1;
1✔
1134
            return this;
1✔
1135
        }
1136

1137
        /**
1138
         * Set the subject delete marker TTL duration. Server accepts 1 second or more.
1139
         * null has the effect of clearing the subject delete marker TTL
1140
         * @param subjectDeleteMarkerTtl the TTL duration
1141
         * @return The Builder
1142
         */
1143
        public Builder subjectDeleteMarkerTtl(Duration subjectDeleteMarkerTtl) {
1144
            this.subjectDeleteMarkerTtl = validateDurationNotRequiredGtOrEqSeconds(1, subjectDeleteMarkerTtl, null, "Subject Delete Marker Ttl");
1✔
1145
            return this;
1✔
1146
        }
1147

1148
        /**
1149
         * Set the subject delete marker TTL duration in milliseconds. Server accepts 1 second or more.
1150
         * 0 or less has the effect of clearing the subject delete marker TTL
1151
         * @param subjectDeleteMarkerTtlMillis the TTL duration in milliseconds
1152
         * @return The Builder
1153
         */
1154
        public Builder subjectDeleteMarkerTtl(long subjectDeleteMarkerTtlMillis) {
1155
            this.subjectDeleteMarkerTtl = subjectDeleteMarkerTtlMillis <= 0 ? null
1✔
NEW
1156
                : validateDurationGtOrEqSeconds(1, subjectDeleteMarkerTtlMillis, "Subject Delete Marker Ttl");
×
NEW
1157
            return this;
×
1158
        }
1159

1160
        /**
1161
         * Set allow per message TTL to true
1162
         * @return The Builder
1163
         */
1164
        public Builder allowMessageTtl() {
1165
            this.allowMessageTtl = true;
1✔
1166
            return this;
1✔
1167
        }
1168

1169
        /**
1170
         * Set the allow per message TTL flag
1171
         * @param allowMessageTtl the flag
1172
         * @return The Builder
1173
         */
1174
        public Builder allowMessageTtl(boolean allowMessageTtl) {
1175
            this.allowMessageTtl = allowMessageTtl;
1✔
1176
            return this;
1✔
1177
        }
1178

1179
        /**
1180
         * Set to allow message Schedules to true
1181
         * @return The Builder
1182
         */
1183
        public Builder allowMessageSchedules() {
1184
            this.allowMsgSchedules = true;
1✔
1185
            return this;
1✔
1186
        }
1187

1188
        /**
1189
         * Set allow message Schedules flag
1190
         * @param allowMessageSchedules the flag
1191
         * @return The Builder
1192
         */
1193
        public Builder allowMessageSchedules(boolean allowMessageSchedules) {
1194
            this.allowMsgSchedules = allowMessageSchedules;
1✔
1195
            return this;
1✔
1196
        }
1197

1198
        /**
1199
         * Set allow message counter to true
1200
         * @return The Builder
1201
         */
1202
        public Builder allowMessageCounter() {
1203
            this.allowMessageCounter = true;
1✔
1204
            return this;
1✔
1205
        }
1206

1207
        /**
1208
         * Set the allow message counter flag
1209
         * @param allowMessageCounter the flag
1210
         * @return The Builder
1211
         */
1212
        public Builder allowMessageCounter(boolean allowMessageCounter) {
1213
            this.allowMessageCounter = allowMessageCounter;
1✔
1214
            return this;
1✔
1215
        }
1216

1217
        /**
1218
         * Set allow atomic publish to true
1219
         * @return The Builder
1220
         */
1221
        public Builder allowAtomicPublish() {
1222
            this.allowAtomicPublish = true;
1✔
1223
            return this;
1✔
1224
        }
1225

1226
        /**
1227
         * Set allow atomic publish flag
1228
         * @param allowAtomicPublish the flag
1229
         * @return The Builder
1230
         */
1231
        public Builder allowAtomicPublish(boolean allowAtomicPublish) {
1232
            this.allowAtomicPublish = allowAtomicPublish;
1✔
1233
            return this;
1✔
1234
        }
1235

1236
        /**
1237
         * Builds the StreamConfiguration
1238
         * @return a stream configuration.
1239
         */
1240
        public StreamConfiguration build() {
1241
            if (nullOrEmpty(name)) {
1✔
1242
                throw new IllegalArgumentException("Configuration must have a valid stream name");
1✔
1243
            }
1244

1245
            return new StreamConfiguration(this);
1✔
1246
        }
1247
    }
1248
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc