Skip to content

Commit f6d2fd7

Browse files
authored
Move CLI options to Mixin classes (#383)
1 parent ec6a796 commit f6d2fd7

File tree

8 files changed

+258
-42
lines changed

8 files changed

+258
-42
lines changed

streams-bootstrap-cli/src/main/java/com/bakdata/kafka/KafkaApplication.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@
5050
* This class provides the following configuration options:
5151
* <ul>
5252
* <li>{@link #bootstrapServers}</li>
53-
* <li>{@link #outputTopic}</li>
54-
* <li>{@link #labeledOutputTopics}</li>
5553
* <li>{@link #schemaRegistryUrl}</li>
5654
* <li>{@link #kafkaConfig}</li>
5755
* </ul>
@@ -82,11 +80,6 @@ public abstract class KafkaApplication<R extends Runner, CR extends CleanUpRunne
8280
// ConcurrentLinkedDeque required because calling #stop() causes asynchronous #run() calls to finish and thus
8381
// concurrently iterating and removing from #runners
8482
private final ConcurrentLinkedDeque<Stoppable> activeApps = new ConcurrentLinkedDeque<>();
85-
@CommandLine.Option(names = "--output-topic", description = "Output topic")
86-
private String outputTopic;
87-
@CommandLine.Option(names = "--labeled-output-topics", split = ",",
88-
description = "Additional labeled output topics")
89-
private Map<String, String> labeledOutputTopics = emptyMap();
9083
@CommandLine.Option(names = {"--bootstrap-servers", "--bootstrap-server"}, required = true,
9184
description = "Kafka bootstrap servers to connect to")
9285
private String bootstrapServers;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 bakdata
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.bakdata.kafka.mixin;
26+
27+
import lombok.Getter;
28+
import lombok.NoArgsConstructor;
29+
import lombok.Setter;
30+
import picocli.CommandLine;
31+
32+
/**
33+
* Shared CLI options to configure Kafka applications with an error topic.
34+
*/
35+
@Getter
36+
@Setter
37+
@NoArgsConstructor
38+
public class ErrorOptions {
39+
@CommandLine.Option(names = "--error-topic", description = "Error topic")
40+
private String errorTopic;
41+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 bakdata
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.bakdata.kafka.mixin;
26+
27+
import static java.util.Collections.emptyList;
28+
import static java.util.Collections.emptyMap;
29+
30+
import com.bakdata.kafka.StringListConverter;
31+
import java.util.List;
32+
import java.util.Map;
33+
import java.util.regex.Pattern;
34+
import lombok.Getter;
35+
import lombok.NoArgsConstructor;
36+
import lombok.Setter;
37+
import picocli.CommandLine;
38+
import picocli.CommandLine.UseDefaultConverter;
39+
40+
/**
41+
* Shared CLI options to configure Kafka applications that consume input data.
42+
*/
43+
@Getter
44+
@Setter
45+
@NoArgsConstructor
46+
public class InputOptions {
47+
@CommandLine.Option(names = "--input-topics", description = "Input topics", split = ",")
48+
private List<String> inputTopics = emptyList();
49+
@CommandLine.Option(names = "--input-pattern", description = "Input pattern")
50+
private Pattern inputPattern;
51+
@CommandLine.Option(names = "--labeled-input-topics", split = ",", description = "Additional labeled input topics",
52+
converter = {UseDefaultConverter.class, StringListConverter.class})
53+
private Map<String, List<String>> labeledInputTopics = emptyMap();
54+
@CommandLine.Option(names = "--labeled-input-patterns", split = ",",
55+
description = "Additional labeled input patterns")
56+
private Map<String, Pattern> labeledInputPatterns = emptyMap();
57+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 bakdata
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.bakdata.kafka.mixin;
26+
27+
import static java.util.Collections.emptyMap;
28+
29+
import java.util.Map;
30+
import lombok.Getter;
31+
import lombok.NoArgsConstructor;
32+
import lombok.Setter;
33+
import picocli.CommandLine;
34+
35+
/**
36+
* Shared CLI options to configure Kafka applications that produce output data.
37+
*/
38+
@Getter
39+
@Setter
40+
@NoArgsConstructor
41+
public class OutputOptions {
42+
@CommandLine.Option(names = "--output-topic", description = "Output topic")
43+
private String outputTopic;
44+
@CommandLine.Option(names = "--labeled-output-topics", split = ",",
45+
description = "Additional labeled output topics")
46+
private Map<String, String> labeledOutputTopics = emptyMap();
47+
}

streams-bootstrap-cli/src/main/java/com/bakdata/kafka/producer/KafkaProducerApplication.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,25 @@
2525
package com.bakdata.kafka.producer;
2626

2727
import com.bakdata.kafka.KafkaApplication;
28+
import com.bakdata.kafka.mixin.OutputOptions;
2829
import java.util.Optional;
2930
import lombok.Getter;
3031
import lombok.RequiredArgsConstructor;
3132
import lombok.Setter;
3233
import lombok.ToString;
34+
import lombok.experimental.Delegate;
3335
import lombok.extern.slf4j.Slf4j;
3436
import picocli.CommandLine.Command;
37+
import picocli.CommandLine.Mixin;
3538

3639

3740
/**
3841
* <p>The base class for creating Kafka Producer applications.</p>
39-
* This class provides all configuration options provided by {@link KafkaApplication}.
42+
* This class provides the following configuration options in addition to those provided by {@link KafkaApplication}:
43+
* <ul>
44+
* <li>{@link #getOutputTopic()}</li>
45+
* <li>{@link #getLabeledOutputTopics()}</li>
46+
* </ul>
4047
* To implement your Kafka Producer application inherit from this class and add your custom options. Run it by
4148
* creating an instance of your class and calling {@link #startApplication(String[])} from your main.
4249
*
@@ -51,6 +58,9 @@
5158
public abstract class KafkaProducerApplication<T extends ProducerApp> extends
5259
KafkaApplication<ProducerRunner, ProducerCleanUpRunner, ProducerExecutionOptions, ExecutableProducerApp<T>,
5360
ConfiguredProducerApp<T>, ProducerTopicConfig, T, ProducerAppConfiguration> {
61+
@Mixin
62+
@Delegate
63+
private OutputOptions outputOptions = new OutputOptions();
5464

5565
/**
5666
* Delete all output topics associated with the Kafka Producer application.

streams-bootstrap-cli/src/main/java/com/bakdata/kafka/streams/KafkaStreamsApplication.java

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,36 @@
2424

2525
package com.bakdata.kafka.streams;
2626

27-
import static java.util.Collections.emptyList;
28-
import static java.util.Collections.emptyMap;
29-
3027
import com.bakdata.kafka.KafkaApplication;
31-
import com.bakdata.kafka.StringListConverter;
32-
import java.util.List;
33-
import java.util.Map;
28+
import com.bakdata.kafka.mixin.ErrorOptions;
29+
import com.bakdata.kafka.mixin.InputOptions;
30+
import com.bakdata.kafka.mixin.OutputOptions;
3431
import java.util.Optional;
35-
import java.util.regex.Pattern;
3632
import lombok.Getter;
3733
import lombok.RequiredArgsConstructor;
3834
import lombok.Setter;
3935
import lombok.ToString;
36+
import lombok.experimental.Delegate;
4037
import lombok.extern.slf4j.Slf4j;
4138
import org.apache.kafka.streams.KafkaStreams;
4239
import org.apache.kafka.streams.KafkaStreams.StateListener;
4340
import org.apache.kafka.streams.StreamsConfig;
4441
import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler;
4542
import picocli.CommandLine;
4643
import picocli.CommandLine.Command;
47-
import picocli.CommandLine.UseDefaultConverter;
48-
44+
import picocli.CommandLine.Mixin;
4945

5046
/**
5147
* <p>The base class for creating Kafka Streams applications.</p>
5248
* This class provides the following configuration options in addition to those provided by {@link KafkaApplication}:
5349
* <ul>
54-
* <li>{@link #inputTopics}</li>
55-
* <li>{@link #inputPattern}</li>
56-
* <li>{@link #errorTopic}</li>
57-
* <li>{@link #labeledInputTopics}</li>
58-
* <li>{@link #labeledInputPatterns}</li>
50+
* <li>{@link #getInputTopics()}</li>
51+
* <li>{@link #getInputPattern()}</li>
52+
* <li>{@link #getLabeledInputTopics()}</li>
53+
* <li>{@link #getLabeledInputPatterns()}</li>
54+
* <li>{@link #getOutputTopic()}</li>
55+
* <li>{@link #getLabeledOutputTopics()}</li>
56+
* <li>{@link #getErrorTopic()}</li>
5957
* <li>{@link #volatileGroupInstanceId}</li>
6058
* </ul>
6159
* To implement your Kafka Streams application inherit from this class and add your custom options. Run it by
@@ -72,32 +70,29 @@
7270
public abstract class KafkaStreamsApplication<T extends StreamsApp> extends
7371
KafkaApplication<StreamsRunner, StreamsCleanUpRunner, StreamsExecutionOptions,
7472
ExecutableStreamsApp<T>, ConfiguredStreamsApp<T>, StreamsTopicConfig, T, StreamsAppConfiguration> {
75-
@CommandLine.Option(names = "--input-topics", description = "Input topics", split = ",")
76-
private List<String> inputTopics = emptyList();
77-
@CommandLine.Option(names = "--input-pattern", description = "Input pattern")
78-
private Pattern inputPattern;
79-
@CommandLine.Option(names = "--error-topic", description = "Error topic")
80-
private String errorTopic;
81-
@CommandLine.Option(names = "--labeled-input-topics", split = ",", description = "Additional labeled input topics",
82-
converter = {UseDefaultConverter.class, StringListConverter.class})
83-
private Map<String, List<String>> labeledInputTopics = emptyMap();
84-
@CommandLine.Option(names = "--labeled-input-patterns", split = ",",
85-
description = "Additional labeled input patterns")
86-
private Map<String, Pattern> labeledInputPatterns = emptyMap();
73+
@Mixin
74+
@Delegate
75+
private InputOptions inputOptions = new InputOptions();
76+
@Mixin
77+
@Delegate
78+
private OutputOptions outputOptions = new OutputOptions();
79+
@Mixin
80+
@Delegate
81+
private ErrorOptions errorOptions = new ErrorOptions();
8782
@CommandLine.Option(names = "--volatile-group-instance-id", arity = "0..1",
8883
description = "Whether the group instance id is volatile, i.e., it will change on a Streams shutdown.")
8984
private boolean volatileGroupInstanceId;
9085
@CommandLine.Option(names = "--application-id",
9186
description = "Unique application ID to use for Kafka Streams. Can also be provided by implementing "
92-
+ "StreamsApp#getUniqueAppId()")
87+
+ "StreamsApp#getUniqueAppId()")
9388
private String applicationId;
9489

9590
/**
9691
* Reset the Kafka Streams application. Additionally, delete the consumer group and all output and intermediate
9792
* topics associated with the Kafka Streams application.
9893
*/
9994
@Command(description = "Reset the Kafka Streams application. Additionally, delete the consumer group and all "
100-
+ "output and intermediate topics associated with the Kafka Streams application.")
95+
+ "output and intermediate topics associated with the Kafka Streams application.")
10196
@Override
10297
public void clean() {
10398
super.clean();
@@ -108,7 +103,7 @@ public void clean() {
108103
* application.
109104
*/
110105
@Command(description = "Clear all state stores, consumer group offsets, and internal topics associated with the "
111-
+ "Kafka Streams application.")
106+
+ "Kafka Streams application.")
112107
public void reset() {
113108
this.prepareClean();
114109
try (final CleanableApp<StreamsCleanUpRunner> app = this.createCleanableApp()) {
@@ -131,13 +126,13 @@ public final Optional<StreamsExecutionOptions> createExecutionOptions() {
131126
@Override
132127
public final StreamsTopicConfig createTopicConfig() {
133128
return StreamsTopicConfig.builder()
134-
.inputTopics(this.inputTopics)
135-
.labeledInputTopics(this.labeledInputTopics)
136-
.inputPattern(this.inputPattern)
137-
.labeledInputPatterns(this.labeledInputPatterns)
129+
.inputTopics(this.getInputTopics())
130+
.labeledInputTopics(this.getLabeledInputTopics())
131+
.inputPattern(this.getInputPattern())
132+
.labeledInputPatterns(this.getLabeledInputPatterns())
138133
.outputTopic(this.getOutputTopic())
139134
.labeledOutputTopics(this.getLabeledOutputTopics())
140-
.errorTopic(this.errorTopic)
135+
.errorTopic(this.getErrorTopic())
141136
.build();
142137
}
143138

0 commit comments

Comments
 (0)