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

nats-io / java-nats-server-runner / #9

26 Oct 2023 06:54PM UTC coverage: 86.318% (+3.1%) from 83.26%
#9

push

github-actions

web-flow
1.2.6 Better failure error reporting. (#27)

58 of 58 new or added lines in 3 files covered. (100.0%)

429 of 497 relevant lines covered (86.32%)

0.86 hits per line

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

96.71
/src/main/java/nats/io/NatsServerRunner.java
1
// Copyright 2020-2023 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 nats.io;
15

16
import java.io.*;
17
import java.net.ConnectException;
18
import java.net.InetSocketAddress;
19
import java.net.SocketAddress;
20
import java.nio.channels.SocketChannel;
21
import java.nio.file.Files;
22
import java.nio.file.Path;
23
import java.nio.file.Paths;
24
import java.util.ArrayList;
25
import java.util.Arrays;
26
import java.util.List;
27
import java.util.function.Supplier;
28
import java.util.logging.Level;
29
import java.util.logging.Logger;
30
import java.util.regex.Matcher;
31
import java.util.regex.Pattern;
32

33
import static nats.io.NatsRunnerUtils.*;
34

35
/**
36
 * Server Runner
37
 */
38
public class NatsServerRunner implements AutoCloseable {
39
    public static final String ERROR_NOTE_PART_1 = "Make sure that the nats-server is installed and in your PATH.";
40
    public static final String ERROR_NOTE_PART_2 = "See https://github.com/nats-io/nats-server for information on installation";
41
    public static long DEFAULT_PROCESS_CHECK_WAIT = 100;
1✔
42
    public static int DEFAULT_PROCESS_CHECK_TRIES = 10;
1✔
43
    public static long DEFAULT_RUN_CHECK_WAIT = 100;
1✔
44
    public static int DEFAULT_RUN_CHECK_TRIES = 3;
1✔
45

46
    private final String _executablePath;
47
    private final Output _displayOut;
48
    private final int _port;
49
    private final File _configFile;
50
    private final String _cmdLine;
51
    private Process process;
52

53
    /**
54
     * Get a new Builder
55
     * @return the builder
56
     */
57
    public static Builder builder() {
58
        return new Builder();
1✔
59
    }
60

61
    /**
62
     * Construct and start the Nats Server runner with all defaults:
63
     * <ul>
64
     * <li>use an automatically allocated port</li>
65
     * <li>no debug flag</li>
66
     * <li>jetstream not enabled</li>
67
     * <li>no custom config file</li>
68
     * <li>no config inserts</li>
69
     * <li>no custom args</li>
70
     * </ul>
71
     * @throws IOException thrown when the server cannot start
72
     */
73
    public NatsServerRunner() throws IOException {
74
        this(builder());
1✔
75
    }
1✔
76

77
    /**
78
     * Construct and start the Nats Server runner with defaults:
79
     * <ul>
80
     * <li>use an automatically allocated port</li>
81
     * <li>jetstream not enabled</li>
82
     * <li>no custom config file</li>
83
     * <li>no config inserts</li>
84
     * <li>no custom args</li>
85
     * </ul>
86
     * and this option:
87
     * @param debug whether to start the server with the -DV flags
88
     * @throws IOException thrown when the server cannot start
89
     */
90
    public NatsServerRunner(boolean debug) throws IOException {
91
        this(builder().debug(debug));
1✔
92
    }
1✔
93

94
    /**
95
     * Construct and start the Nats Server runner with defaults:
96
     * Consider using {@link Builder}
97
     * <ul>
98
     * <li>use an automatically allocated port</li>
99
     * <li>no custom config file</li>
100
     * <li>no config inserts</li>
101
     * <li>no custom args</li>
102
     * </ul>
103
     * and these options:
104
     * @param debug whether to start the server with the -DV flags
105
     * @param jetstream whether to enable JetStream
106
     * @throws IOException thrown when the server cannot start
107
     */
108
    public NatsServerRunner(boolean debug, boolean jetstream) throws IOException {
109
        this(builder().debug(debug).jetstream(jetstream));
1✔
110
    }
1✔
111

112
    /**
113
     * Construct and start the Nats Server runner with defaults:
114
     * <ul>
115
     * <li>jetstream not enabled</li>
116
     * <li>no custom config file</li>
117
     * <li>no config inserts</li>
118
     * <li>no custom args</li>
119
     * </ul>
120
     * and these options:
121
     * @param port the port to start on or &lt;=0 to use an automatically allocated port
122
     * @param debug whether to start the server with the -DV flags
123
     * @throws IOException thrown when the server cannot start
124
     */
125
    public NatsServerRunner(int port, boolean debug) throws IOException {
126
        this(builder().port(port).debug(debug));
1✔
127
    }
1✔
128

129
    /**
130
     * Construct and start the Nats Server runner with defaults:
131
     * <ul>
132
     * <li>no custom config file</li>
133
     * <li>no config inserts</li>
134
     * <li>no custom args</li>
135
     * </ul>
136
     * and these options:
137
     * @param port the port to start on or &lt;=0 to use an automatically allocated port
138
     * @param debug whether to start the server with the -DV flags
139
     * @param jetstream whether to enable JetStream
140
     * @throws IOException thrown when the server cannot start
141
     */
142
    public NatsServerRunner(int port, boolean debug, boolean jetstream) throws IOException {
143
        this(builder().port(port).debug(debug).jetstream(jetstream));
1✔
144
    }
1✔
145

146
    /**
147
     * Construct and start the Nats Server runner with defaults:
148
     * Consider using {@link Builder}
149
     * <ul>
150
     * <li>use an automatically allocated port</li>
151
     * <li>jetstream not enabled</li>
152
     * <li>no config inserts</li>
153
     * <li>no custom args</li>
154
     * </ul>
155
     * and these options:
156
     * @param debug whether to start the server with the -DV flags
157
     * @param configFilePath path to a custom config file
158
     * @throws IOException thrown when the server cannot start
159
     */
160
    public NatsServerRunner(String configFilePath, boolean debug) throws IOException {
161
        this(builder().debug(debug).configFilePath(configFilePath));
1✔
162
    }
1✔
163

164
    /**
165
     * Construct and start the Nats Server runner with defaults:
166
     * Consider using {@link Builder}
167
     * <ul>
168
     * <li>use an automatically allocated port</li>
169
     * <li>jetstream not enabled</li>
170
     * <li>no custom config file</li>
171
     * </ul>
172
     * and these options:
173
     * @param debug whether to start the server with the -DV flags
174
     * @param jetstream whether to enable JetStream
175
     * @param configFilePath path to a custom config file
176
     * @throws IOException thrown when the server cannot start
177
     */
178
    public NatsServerRunner(String configFilePath, boolean debug, boolean jetstream) throws IOException {
179
        this(builder().debug(debug).jetstream(jetstream).configFilePath(configFilePath));
1✔
180
    }
1✔
181

182
    /**
183
     * Construct and start the Nats Server runner with defaults:
184
     * Consider using {@link Builder}
185
     * <ul>
186
     * <li>jetstream not enabled</li>
187
     * <li>no custom args</li>
188
     * </ul>
189
     * and these options:
190
     * @param port the port to start on or &lt;=0 to use an automatically allocated port
191
     * @param debug whether to start the server with the -DV flags
192
     * @param configFilePath path to a custom config file
193
     * @param configInserts an array of custom lines to add to the config file
194
     * @throws IOException thrown when the server cannot start
195
     */
196
    public NatsServerRunner(String configFilePath, String[] configInserts, int port, boolean debug) throws IOException {
197
        this(builder().port(port).debug(debug).configFilePath(configFilePath).configInserts(configInserts));
1✔
198
    }
1✔
199

200
    /**
201
     * Construct and start the Nats Server runner with defaults:
202
     * Consider using {@link Builder}
203
     * <ul>
204
     * <li>jetstream not enabled</li>
205
     * <li>no config inserts</li>
206
     * <li>no custom args</li>
207
     * </ul>
208
     * and these options:
209
     * @param port the port to start on or &lt;=0 to use an automatically allocated port
210
     * @param debug whether to start the server with the -DV flags
211
     * @param configFilePath path to a custom config file
212
     * @throws IOException thrown when the server cannot start
213
     */
214
    public NatsServerRunner(String configFilePath, int port, boolean debug) throws IOException {
215
        this(builder().port(port).debug(debug).configFilePath(configFilePath));
1✔
216
    }
1✔
217

218
    /**
219
     * Construct and start the Nats Server runner with defaults:
220
     * Consider using {@link Builder}
221
     * <ul>
222
     * <li>use an automatically allocated port</li>
223
     * <li>no debug flag</li>
224
     * <li>jetstream not enabled</li>
225
     * <li>no custom config file</li>
226
     * <li>no config inserts</li>
227
     * </ul>
228
     * and these options:
229
     * @param customArgs any custom args to add to the command line
230
     * @throws IOException thrown when the server cannot start
231
     */
232
    public NatsServerRunner(String[] customArgs) throws IOException {
233
        this(builder().customArgs(customArgs));
1✔
234
    }
1✔
235

236
    /**
237
     * Construct and start the Nats Server runner with defaults:
238
     * Consider using {@link Builder}
239
     * <ul>
240
     * <li>use an automatically allocated port</li>
241
     * <li>jetstream not enabled</li>
242
     * <li>no custom config file</li>
243
     * <li>no config inserts</li>
244
     * </ul>
245
     * and these options:
246
     * @param debug whether to start the server with the -DV flags
247
     * @param customArgs any custom args to add to the command line
248
     * @throws IOException thrown when the server cannot start
249
     */
250
    public NatsServerRunner(String[] customArgs, boolean debug) throws IOException {
251
        this(builder().debug(debug).customArgs(customArgs));
1✔
252
    }
1✔
253

254
    /**
255
     * Construct and start the Nats Server runner with defaults:
256
     * Consider using {@link Builder}
257
     * <ul>
258
     * <li>use an automatically allocated port</li>
259
     * <li>no custom config file</li>
260
     * <li>no config inserts</li>
261
     * </ul>
262
     * and these options:
263
     * @param customArgs any custom args to add to the command line
264
     * @param debug whether to start the server with the -DV flags
265
     * @param jetstream whether to enable JetStream
266
     * @throws IOException thrown when the server cannot start
267
     */
268
    public NatsServerRunner(String[] customArgs, boolean debug, boolean jetstream) throws IOException {
269
        this(builder().debug(debug).jetstream(jetstream).customArgs(customArgs));
1✔
270
    }
1✔
271

272
    /**
273
     * Construct and start the Nats Server runner with defaults:
274
     * Consider using {@link Builder}
275
     * <ul>
276
     * <li>jetstream not enabled</li>
277
     * <li>no custom config file</li>
278
     * <li>no config inserts</li>
279
     * </ul>
280
     * and these options:
281
     * @param customArgs any custom args to add to the command line
282
     * @param port the port to start on or &lt;=0 to use an automatically allocated port
283
     * @param debug whether to start the server with the -DV flags
284
     * @throws IOException thrown when the server cannot start
285
     */
286
    public NatsServerRunner(String[] customArgs, int port, boolean debug) throws IOException {
287
        this(builder().port(port).debug(debug).customArgs(customArgs));
×
288
    }
×
289

290
    /**
291
     * Construct and start the Nats Server runner with options
292
     * Consider using {@link Builder}
293
     * @param port the port to start on or &lt;=0 to use an automatically allocated port
294
     * @param debug whether to start the server with the -DV flags
295
     * @param jetstream whether to enable JetStream
296
     * @param configFilePath path to a custom config file
297
     * @param configInserts an array of custom lines to add to the config file
298
     * @param customArgs any custom args to add to the command line
299
     * @throws IOException thrown when the server cannot start
300
     */
301
    public NatsServerRunner(int port, boolean debug, boolean jetstream, String configFilePath, String[] configInserts, String[] customArgs) throws IOException {
302
        this(builder().port(port).debug(debug).jetstream(jetstream).configFilePath(configFilePath).configInserts(configInserts).customArgs(customArgs));
1✔
303
    }
1✔
304

305
    public NatsServerRunner(NatsServerRunnerOptions natsServerRunnerOptions) throws Exception {
306
        this(builder().runnerOptions(natsServerRunnerOptions));
1✔
307
    }
1✔
308

309
    // ----------------------------------------------------------------------------------------------------
310
    // ACTUAL CONSTRUCTION
311
    // ----------------------------------------------------------------------------------------------------
312
    protected NatsServerRunner(Builder b) throws IOException {
1✔
313
        _executablePath = b.executablePath == null ? getResolvedServerPath() : b.executablePath.toString();
1✔
314
        _port = b.port == null || b.port <= 0 ? nextPort() : b.port;
1✔
315

316
        if (b.output == null) {
1✔
317
            _displayOut = DefaultOutputSupplier.get();
1✔
318
            _displayOut.setLevel(DefaultOutputLevel);
1✔
319
        }
320
        else {
321
            _displayOut = b.output;
1✔
322
            if (b.outputLevel != null) {
1✔
323
                _displayOut.setLevel(b.outputLevel);
×
324
            }
325
        }
326

327
        long procCheckWait = b.processCheckWait == null ? DEFAULT_PROCESS_CHECK_WAIT : b.processCheckWait;
1✔
328
        int procCheckTries = b.processCheckTries == null ? DEFAULT_PROCESS_CHECK_TRIES : b.processCheckTries;
1✔
329
        long connCheckWait = b.connectCheckWait == null ? DEFAULT_RUN_CHECK_WAIT : b.connectCheckWait;
1✔
330
        int connCheckTries = b.connectCheckTries == null ? DEFAULT_RUN_CHECK_TRIES : b.connectCheckTries;
1✔
331

332
        List<String> cmd = new ArrayList<>();
1✔
333
        cmd.add(_executablePath);
1✔
334

335
        try {
336
            _configFile = File.createTempFile(CONF_FILE_PREFIX, CONF_FILE_EXT);
1✔
337
            BufferedWriter writer = new BufferedWriter(new FileWriter(_configFile));
1✔
338
            if (b.configFilePath == null || processSuppliedConfigFile(writer, b.configFilePath)) {
1✔
339
                writePortLine(writer, _port);
1✔
340
            }
341

342
            if (b.configInserts != null) {
1✔
343
                for (String s : b.configInserts) {
1✔
344
                    writeLine(writer, s);
1✔
345
                }
1✔
346
            }
347

348
            writer.flush();
1✔
349
            writer.close();
1✔
350

351
            cmd.add(CONFIG_FILE_OPTION_NAME);
1✔
352
            cmd.add(_configFile.getAbsolutePath());
1✔
353
        }
354
        catch (IOException ioe) {
1✔
355
            _displayOut.error("%%% Error creating config file: " + ioe);
1✔
356
            throw ioe;
1✔
357
        }
1✔
358

359
        // Rewrite the port to a new one, so we don't reuse the same one over and over
360

361
        if (b.jetstream) {
1✔
362
            cmd.add(JETSTREAM_OPTION);
1✔
363
        }
364

365
        if (b.customArgs != null) {
1✔
366
            cmd.addAll(b.customArgs);
1✔
367
        }
368

369
        if (b.debugLevel != null) {
1✔
370
            cmd.add(b.debugLevel.getCmdOption());
1✔
371
        }
372

373
        _cmdLine = String.join(" ", cmd);
1✔
374

375
        NatsOutputLogger nol = null;
1✔
376
        try {
377
            ProcessBuilder pb = new ProcessBuilder(cmd);
1✔
378
            pb.redirectErrorStream(true);
1✔
379
            pb.redirectError(ProcessBuilder.Redirect.PIPE);
1✔
380
            pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
1✔
381
            _displayOut.info("%%% Starting [" + _cmdLine + "] with redirected IO");
1✔
382

383
            process = pb.start();
1✔
384
            nol = NatsOutputLogger.logOutput(_displayOut, process, DEFAULT_NATS_SERVER);
1✔
385

386
            int tries = procCheckTries;
1✔
387
            do {
388
                sleep(procCheckWait);
1✔
389
            }
390
            while (!process.isAlive() && --tries > 0);
1✔
391

392
            SocketAddress addr = new InetSocketAddress("localhost", _port);
1✔
393
            SocketChannel socketChannel = SocketChannel.open();
1✔
394
            socketChannel.configureBlocking(true);
1✔
395
            if (connCheckTries > 0) {
1✔
396
                boolean checking = true;
1✔
397
                tries = connCheckTries;
1✔
398
                do {
399
                    try {
400
                        socketChannel.connect(addr);
1✔
401
                        checking = false;
1✔
402
                    }
403
                    catch (ConnectException e) {
1✔
404
                        if (--tries == 0) {
1✔
405
                            throw e;
×
406
                        }
407
                        sleep(connCheckWait);
1✔
408
                    } finally {
409
                        socketChannel.close();
1✔
410
                    }
411
                } while (checking);
1✔
412
            }
413

414
            _displayOut.info("%%% Started [" + _cmdLine + "]");
1✔
415
            nol.endStartupPhase();
1✔
416
        }
417
        catch (IOException ex) {
1✔
418
            _displayOut.error("%%% Failed to run [" + _cmdLine + "]");
1✔
419
            String exMsg = ex.getMessage();
1✔
420
            if (exMsg != null) {
1✔
421
                _displayOut.error("    " + ex.getMessage());
×
422
            }
423
            _displayOut.error("%%% " + ERROR_NOTE_PART_1);
1✔
424
            _displayOut.error("%%% " + ERROR_NOTE_PART_2);
1✔
425
            StringBuilder exMessage = new StringBuilder("Failed to run [").append(_cmdLine).append("]");
1✔
426
            if (b.fullErrorReportOnStartup) {
1✔
427
                if (nol != null) {
1✔
428
                    for (String line : nol.getStartupLines()) {
1✔
429
                        exMessage.append(System.lineSeparator()).append(line);
1✔
430
                    }
1✔
431
                }
432
                if (_cmdLine.contains(CONFIG_FILE_OPTION_NAME)) {
1✔
433
                    String configPath = _configFile.getAbsolutePath();
1✔
434
                    String configSep = getConfigSep(configPath);
1✔
435
                    exMessage.append(System.lineSeparator()).append(configSep);
1✔
436
                    exMessage.append(System.lineSeparator()).append(configPath);
1✔
437
                    exMessage.append(System.lineSeparator()).append(configSep);
1✔
438
                    try {
439
                        List<String> lines = Files.readAllLines(_configFile.toPath());
1✔
440
                        for (String line : lines) {
1✔
441
                            exMessage.append(System.lineSeparator()).append(line);
1✔
442
                        }
1✔
443
                    }
444
                    catch (Exception ignore) {
×
445
                    }
1✔
446
                    exMessage.append(System.lineSeparator()).append(configSep);
1✔
447
                }
448
            }
449
            throw new IllegalStateException(exMessage.toString());
1✔
450
        }
1✔
451
    }
1✔
452

453
    private String getConfigSep(String configPath) {
454
        StringBuilder sep = new StringBuilder("------------------------------");
1✔
455
        int len = configPath.length();
1✔
456
        while (sep.length() < len) {
1✔
457
            sep.append(sep);
1✔
458
        }
459
        return sep.substring(0, len);
1✔
460
    }
461

462
    // ----------------------------------------------------------------------------------------------------
463
    // HELPERS
464
    // ----------------------------------------------------------------------------------------------------
465
    private boolean processSuppliedConfigFile(BufferedWriter writer, Path configFilePath) throws IOException {
466
        Pattern portPattern = Pattern.compile(PORT_REGEX);
1✔
467
        Matcher portMatcher = portPattern.matcher("");
1✔
468

469
        BufferedReader reader = new BufferedReader(new FileReader(configFilePath.toFile()));
1✔
470

471
        boolean needsPortLine = true;
1✔
472
        String line = reader.readLine();
1✔
473
        while (line != null) {
1✔
474
            portMatcher.reset(line);
1✔
475

476
            // replacing it here allows us to not care if the port is at the top level
477
            // or for instance inside a websocket block
478
            if (portMatcher.find()) {
1✔
479
                writeLine(writer, line.replace(portMatcher.group(1), String.valueOf(_port)));
1✔
480
                needsPortLine = false;
1✔
481
            }
482
            else {
483
                writeLine(writer, line);
1✔
484
            }
485

486
            line = reader.readLine();
1✔
487
        }
488

489
        reader.close();
1✔
490

491
        return needsPortLine;
1✔
492
    }
493

494
    private void writePortLine(BufferedWriter writer, int port) throws IOException {
495
        writeLine(writer, PORT_PROPERTY + port);
1✔
496
    }
1✔
497

498
    private void writeLine(BufferedWriter writer, String line) throws IOException {
499
        writer.write(line);
1✔
500
        writer.write("\n");
1✔
501
    }
1✔
502

503
    private void sleep(long sleep) {
504
        try {
505
            Thread.sleep(sleep);
1✔
506
        }
507
        catch (Exception ignore) {}
1✔
508
    }
1✔
509

510
    // ====================================================================================================
511
    // Getters
512
    // ====================================================================================================
513
    /**
514
     * The resolved server executable path being used
515
     * @return the path
516
     */
517
    public String getExecutablePath() {
518
        return _executablePath;
1✔
519
    }
520

521
    /**
522
     * Get the port number. Useful if it was automatically assigned
523
     * @return the port number
524
     */
525
    public int getPort() {
526
        return _port;
1✔
527
    }
528

529
    /**
530
     * Get the absolute path of the config file
531
     * @return the path
532
     */
533
    public String getConfigFile() {
534
        return _configFile.getAbsolutePath();
1✔
535
    }
536

537
    /**
538
     * Get the uri in the form nats://localhost:port
539
     * @return the uri string
540
     */
541
    public String getURI() {
542
        return getNatsLocalhostUri(_port);
1✔
543
    }
544

545
    /**
546
     * Get the command line used to start the server
547
     * @return the command line
548
     */
549
    public String getCmdLine() {
550
        return _cmdLine;
1✔
551
    }
552

553
    /**
554
     * Shut the server down
555
     * @param wait whether to block while waiting for the process to shut down
556
     * @throws InterruptedException if the wait was interrupted
557
     */
558
    public void shutdown(boolean wait) throws InterruptedException {
559
        if (process != null) {
1✔
560
            process.destroy();
1✔
561
            _displayOut.info("%%% Shut down [" + _cmdLine + "]");
1✔
562
            if (wait) {
1✔
563
                process.waitFor();
1✔
564
            }
565
            process = null;
1✔
566
        }
567
    }
1✔
568

569
    /**
570
     * Shut the server down, waiting (blocking)
571
     * @throws InterruptedException if the wait was interrupted
572
     */
573
    public void shutdown() throws InterruptedException {
574
        shutdown(true);
1✔
575
    }
1✔
576

577
    /**
578
     * For AutoCloseable, calls shutdown(true).
579
     */
580
    @Override
581
    public void close() throws Exception {
582
        shutdown(true);
1✔
583
    }
1✔
584

585
    // ====================================================================================================
586
    // Builder
587
    // ====================================================================================================
588
    public static class Builder {
1✔
589
        Integer port;
590
        DebugLevel debugLevel;
591
        boolean jetstream;
592
        Path configFilePath;
593
        List<String> configInserts;
594
        List<String> customArgs;
595
        Path executablePath;
596
        Output output;
597
        Level outputLevel;
598
        Long processCheckWait;
599
        Integer processCheckTries;
600
        Long connectCheckWait;
601
        Integer connectCheckTries;
602
        boolean fullErrorReportOnStartup = true;
1✔
603

604
        public Builder port(Integer port) {
605
            this.port = port;
1✔
606
            return this;
1✔
607
        }
608

609
        public Builder debugLevel(DebugLevel debugLevel) {
610
            this.debugLevel = debugLevel;
1✔
611
            return this;
1✔
612
        }
613

614
        public Builder debug(boolean trueForDebugTraceFalseForNoDebug) {
615
            this.debugLevel = trueForDebugTraceFalseForNoDebug ? DebugLevel.DEBUG_TRACE : null;
1✔
616
            return this;
1✔
617
        }
618

619
        public Builder jetstream() {
620
            this.jetstream = true;
1✔
621
            return this;
1✔
622
        }
623

624
        public Builder jetstream(boolean jetStream) {
625
            this.jetstream = jetStream;
1✔
626
            return this;
1✔
627
        }
628

629
        public Builder configFilePath(String configFilePath) {
630
            this.configFilePath = configFilePath == null ? null : Paths.get(configFilePath);
1✔
631
            return this;
1✔
632
        }
633

634
        public Builder configFilePath(Path configFilePath) {
635
            this.configFilePath = configFilePath;
1✔
636
            return this;
1✔
637
        }
638

639
        public Builder configInserts(List<String> configInserts) {
640
            this.configInserts = configInserts == null || configInserts.isEmpty() ? null : configInserts;
1✔
641
            return this;
1✔
642
        }
643

644
        public Builder configInserts(String[] configInserts) {
645
            this.configInserts = configInserts == null || configInserts.length == 0 ? null : Arrays.asList(configInserts);
1✔
646
            return this;
1✔
647
        }
648

649
        public Builder customArgs(List<String> customArgs) {
650
            this.customArgs = customArgs == null || customArgs.isEmpty() ? null : customArgs;
1✔
651
            return this;
1✔
652
        }
653

654
        public Builder customArgs(String[] customArgs) {
655
            this.customArgs = customArgs == null || customArgs.length == 0 ? null : Arrays.asList(customArgs);
1✔
656
            return this;
1✔
657
        }
658

659
        public Builder executablePath(String executablePath) {
660
            this.executablePath = executablePath == null ? null : Paths.get(executablePath);
1✔
661
            return this;
1✔
662
        }
663

664
        public Builder executablePath(Path executablePath) {
665
            this.executablePath = executablePath;
1✔
666
            return this;
1✔
667
        }
668

669
        public Builder output(Output output) {
670
            this.output = output;
1✔
671
            return this;
1✔
672
        }
673

674
        public Builder outputLogger(Logger logger) {
675
            this.output = logger == null ? null : new LoggingOutput(logger);
1✔
676
            return this;
1✔
677
        }
678

679
        public Builder outputLevel(Level level) {
680
            this.outputLevel = level;
1✔
681
            return this;
1✔
682
        }
683

684
        public Builder processCheckWait(Long processWait) {
685
            this.processCheckWait = processWait;
1✔
686
            return this;
1✔
687
        }
688

689
        public Builder processCheckTries(Integer processCheckTries) {
690
            this.processCheckTries = processCheckTries;
1✔
691
            return this;
1✔
692
        }
693

694
        public Builder connectCheckWait(Long connectCheckWait) {
695
            this.connectCheckWait = connectCheckWait;
1✔
696
            return this;
1✔
697
        }
698

699
        public Builder connectCheckTries(Integer connectCheckTries) {
700
            this.connectCheckTries = connectCheckTries;
1✔
701
            return this;
1✔
702
        }
703

704
        public Builder fullErrorReportOnStartup(boolean expandedError) {
705
            this.fullErrorReportOnStartup = expandedError;
×
706
            return this;
×
707
        }
708

709
        public Builder runnerOptions(NatsServerRunnerOptions nsro) {
710
            port(nsro.port())
1✔
711
                .debugLevel(nsro.debugLevel())
1✔
712
                .jetstream(nsro.jetStream())
1✔
713
                .configFilePath(nsro.configFilePath())
1✔
714
                .configInserts(nsro.configInserts())
1✔
715
                .customArgs(nsro.customArgs())
1✔
716
                .executablePath(nsro.executablePath())
1✔
717
                .outputLogger(nsro.logger())
1✔
718
                .outputLevel(nsro.logLevel());
1✔
719
            return this;
1✔
720
        }
721

722
        public NatsServerRunner build() throws IOException {
723
            return new NatsServerRunner(this);
1✔
724
        }
725

726
        public NatsServerRunnerOptions buildOptions() {
727
            return new NatsServerRunnerOptionsImpl(this);
1✔
728
        }
729
    }
730

731
    // ====================================================================================================
732
    // Runner Wide Setting
733
    // ====================================================================================================
734
    static final Supplier<Output> DefaultLoggingSupplier = () -> new LoggingOutput(Logger.getLogger(NatsServerRunner.class.getName()));
1✔
735

736
    private static Supplier<Output> DefaultOutputSupplier = DefaultLoggingSupplier;
1✔
737
    private static Level DefaultOutputLevel = Level.INFO;
1✔
738
    private static String PreferredServerPath = null;
1✔
739

740
    public static Supplier<Output> getDefaultOutputSupplier() {
741
        return DefaultOutputSupplier;
1✔
742
    }
743

744
    public static void setDefaultOutputSupplier(Supplier<Output> outputSupplier) {
745
        DefaultOutputSupplier = outputSupplier == null ? DefaultLoggingSupplier : outputSupplier;
1✔
746
    }
1✔
747

748
    public static Level getDefaultOutputLevel() {
749
        return DefaultOutputLevel;
1✔
750
    }
751

752
    public static void setDefaultOutputLevel(Level defaultOutputLevel) {
753
        DefaultOutputLevel = defaultOutputLevel;
1✔
754
    }
1✔
755

756
    public static String getPreferredServerPath() {
757
        return PreferredServerPath;
1✔
758
    }
759

760
    public static void setPreferredServerPath(String preferredServerPath) {
761
        PreferredServerPath = preferredServerPath == null || preferredServerPath.length() == 0 ? null : preferredServerPath;
1✔
762
    }
1✔
763

764
    public static void clearPreferredServerPath() {
765
        PreferredServerPath = null;
1✔
766
    }
1✔
767
}
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

© 2025 Coveralls, Inc