Skip to content

Commit

Permalink
Merge pull request #462 from hivemq/feature/deprecate-bad-subscribe-o…
Browse files Browse the repository at this point in the history
…ptions

Deprecate bad subscription options and add replacements
  • Loading branch information
LukasBrand authored Oct 7, 2024
2 parents 7b293c9 + 399fe1f commit cd86b31
Show file tree
Hide file tree
Showing 8 changed files with 597 additions and 33 deletions.
18 changes: 9 additions & 9 deletions docs/_includes/options/subscribe-options.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
| Option | Long Version | Explanation | Default |
|--------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| `-t` | `--topic` | The MQTT topic the client will subscribe to. | |
| `-q` | `--qos` | Define the quality of service level. If only one QoS is specified it will be used for all topics.<br> You can define a specific QoS level for every topic. The corresponding QoS levels will be matched in order to the given topics. | `0` |
| `-of` | `--outputToFile` | Append the received publish messages to a file. Creates the file if it does not exist. | |
| `-b64` | `--base64` | Whether the received publish messages will be base64 encoded. | `false` |
| `-J` | `--jsonOutput` | Print the received publishes in pretty JSON format. | `false` |
| `-T` | `--showTopics` | Prepend the specific topic name to the received publish. | `false` |
| `-up` | `--userProperty` | A user property of the subscribe message. | |
| Option | Long Version | Explanation | Default |
|--------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| `-t` | `--topic` | The MQTT topic the client will subscribe to. | |
| `-q` | `--qos` | Define the quality of service level. If only one QoS is specified it will be used for all topics.<br> You can define a specific QoS level for every topic. The corresponding QoS levels will be matched in order to the given topics. | `0` |
| | `--output-to-file` | Append the received publish messages to a file. Creates the file if it does not exist. | |
| | `--base64` | Whether the received publish messages will be base64 encoded. | `false` |
| `-J` | `--json-output` | Print the received publishes in pretty JSON format. | `false` |
| `-T` | `--show-topics` | Prepend the specific topic name to the received publish. | `false` |
| | `--user-property` | A user property of the subscribe message. | |
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import picocli.CommandLine;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;

Expand All @@ -41,6 +43,7 @@
public class SubscribeCommand implements Callable<Integer> {

private static final int IDLE_TIME = 5000;
private final @NotNull List<String> deprecationWarnings = new ArrayList<>();
private final @NotNull MqttClientExecutor mqttClientExecutor;
private @Nullable MqttClient subscribeClient;

Expand All @@ -64,7 +67,7 @@ private void printToSTDOUT(final boolean printToSTDOUT) {
private final @NotNull ConnectOptions connectOptions = new ConnectOptions();

@CommandLine.Mixin
private final @NotNull SubscribeOptions subscribeOptions = new SubscribeOptions();
private final @NotNull SubscribeOptions subscribeOptions = new SubscribeOptions(deprecationWarnings);

@CommandLine.Mixin
private final @NotNull DebugOptions debugOptions = new DebugOptions();
Expand All @@ -90,6 +93,8 @@ public SubscribeCommand(final @NotNull MqttClientExecutor mqttClientExecutor) {

Logger.trace("Command {}", this);

LoggerUtils.logDeprecatedOptions(deprecationWarnings);

connectOptions.setDefaultOptions();
connectOptions.logUnusedOptions();
subscribeOptions.setDefaultOptions();
Expand Down
167 changes: 150 additions & 17 deletions src/main/java/com/hivemq/cli/commands/options/SubscribeOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,17 @@
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class SubscribeOptions {

@SuppressWarnings({"NotNullFieldNotInitialized", "unused"})
@CommandLine.Spec
private @NotNull CommandLine.Model.CommandSpec spec;

private final @NotNull List<String> deprecationWarnings;

@SuppressWarnings({"NotNullFieldNotInitialized", "unused"}) //will be initialized via required
@CommandLine.Option(names = {"-t", "--topic"}, required = true, description = "The topics to subscribe to")
private @NotNull String @NotNull [] topics;
Expand All @@ -48,37 +55,164 @@ public class SubscribeOptions {
description = "Quality of service for the corresponding topics (default for all: 2)")
private @NotNull MqttQos @NotNull [] qos;

private @NotNull Mqtt5UserProperty @Nullable [] userProperties = null;
private boolean userPropertiesFromOption = false;
private boolean userPropertiesFromLegacyOption = false;

@SuppressWarnings("unused")
@CommandLine.Option(names = {"-up", "--userProperty"},
@CommandLine.Option(names = {"--user-property"},
converter = Mqtt5UserPropertyConverter.class,
description = "A user property of the subscribe message")
private @Nullable Mqtt5UserProperty @Nullable [] userProperties;
private void userProperties(final @NotNull Mqtt5UserProperty @NotNull [] userProperties) {
if (userPropertiesFromLegacyOption) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the user properties legacy options \"-up\" or \"--userProperty\" and the current \"--user-property\" is used. Please only use \"--user-property\" as the legacy options will be removed in a future version.");
}
userPropertiesFromOption = true;
this.userProperties = userProperties;
}

@SuppressWarnings("unused")
@CommandLine.Option(names = {"-of", "--outputToFile"},
@Deprecated(since = "4.34.0", forRemoval = true)
@CommandLine.Option(names = {"-up", "--userProperty"},
hidden = true,
converter = Mqtt5UserPropertyConverter.class,
description = "Options \"-up\" and \"--userProperty\" are legacy, please use \"--user-property\". Legacy options will be removed in a future version.")
private void userPropertiesLegacy(final @NotNull Mqtt5UserProperty @NotNull [] userPropertiesLegacy) {
//only show message once as this method is executed multiple times
if (!userPropertiesFromLegacyOption) {
deprecationWarnings.add(
"Options \"-up\" and \"--userProperty\" are legacy, please use \"--user-property\". Legacy options will be removed in a future version.");
}

if (userPropertiesFromOption) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the user properties legacy options \"-up\" or \"--userProperty\" and the current \"--user-property\" is used. Please only use \"--user-property\" as the legacy options will be removed in a future version.");
}
userPropertiesFromLegacyOption = true;
userProperties = userPropertiesLegacy;
}

private @Nullable File outputFile = null;

@SuppressWarnings("unused")
@CommandLine.Option(names = {"--output-to-file"},
description = "A file to which the received publish messages will be written")
private @Nullable File outputFile;
private void outputFile(final @NotNull File outputFile) {
if (this.outputFile != null) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the output file legacy options \"-of\" or \"--outputToFile\" and the current \"--output-to-file\" is used. Please only use \"--output-to-file\" as the legacy options will be removed in a future version.");
}
this.outputFile = outputFile;
}

@SuppressWarnings("unused")
@Deprecated(since = "4.34.0", forRemoval = true)
@CommandLine.Option(names = {"-of", "--outputToFile"},
hidden = true,
description = "Options \"-of\" and \"--outputToFile\" are legacy, please use \"--output-to-file\". Legacy options will be removed in a future version")
private void outputFileLegacy(final @NotNull File outputFileLegacy) {
deprecationWarnings.add(
"Options \"-of\" and \"--outputToFile\" are legacy, please use \"--output-to-file\". Legacy options will be removed in a future version.");

if (this.outputFile != null) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the output file legacy options \"-of\" or \"--outputToFile\" and the current \"--output-to-file\" is used. Please only use \"--output-to-file\" as the legacy options will be removed in a future version.");
}
this.outputFile = outputFileLegacy;
}

private boolean isEncodePayloadInBase64 = false;

@SuppressWarnings("unused")
@CommandLine.Option(names = {"-b64", "--base64"},
@CommandLine.Option(names = {"--base64"},
description = "Specify the encoding of the received messages as Base64 (default: false)")
private boolean base64;
private void isMessageBase64Encoded(final boolean base64) {
if (isEncodePayloadInBase64) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the base64 legacy options \"-b64\" and the current \"--base64\" is used. Please only use \"--base64\" as the legacy options will be removed in a future version.");
}
isEncodePayloadInBase64 = base64;
}

@SuppressWarnings("unused")
@Deprecated(since = "4.34.0", forRemoval = true)
@CommandLine.Option(names = {"-b64"},
hidden = true,
description = "Option \"-b64\" is legacy, please use \"--base64\". The legacy option will be removed in a future version")
private void isMessageBase64EncodedLegacy(final boolean base64Legacy) {
deprecationWarnings.add(
"Option \"-b64\" is legacy, please use \"--base64\". The legacy option will be removed in a future version.");

if (isEncodePayloadInBase64) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the base64 legacy options \"-b64\" and the current \"--base64\" is used. Please only use \"--base64\" as the legacy options will be removed in a future version.");
}
isEncodePayloadInBase64 = base64Legacy;
}

private boolean jsonOutput = false;

@SuppressWarnings("unused")
@CommandLine.Option(names = {"-J", "--jsonOutput"},
defaultValue = "false",
@CommandLine.Option(names = {"-J", "--json-output"},
description = "Print the received publishes in pretty JSON format")
private boolean jsonOutput;
private void jsonOutput(final boolean jsonOutput) {
if (this.jsonOutput) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the json output legacy options \"--jsonOutput\" and the current \"-J\" or \"--json-output\" is used. Please only use \"-J\" or \"--json-output\" as the legacy options will be removed in a future version.");
}
this.jsonOutput = jsonOutput;
}

@SuppressWarnings("unused")
@Deprecated(since = "4.34.0", forRemoval = true)
@CommandLine.Option(names = {"--jsonOutput"},
hidden = true,
description = "Option \"--jsonOutput\" is legacy, please use \"--json-output\". The legacy option will be removed in a future version")
private void jsonOutputLegacy(final boolean jsonOutputLegacy) {
deprecationWarnings.add(
"Option \"--jsonOutput\" is legacy, please use \"--json-output\". The legacy option will be removed in a future version.");

if (jsonOutput) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the json output legacy options \"--jsonOutput\" and the current \"-J\" or \"--json-output\" is used. Please only use \"-J\" or \"--json-output\" as the legacy options will be removed in a future version.");
}
jsonOutput = true;
}

private boolean showTopics = false;

@SuppressWarnings("unused")
@CommandLine.Option(names = {"-T", "--showTopics"},
defaultValue = "false",
@CommandLine.Option(names = {"-T", "--show-topics"},
description = "Prepend the specific topic name to the received publish")
private boolean showTopics;
private void showTopics(final boolean showTopics) {
if (this.showTopics) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the show topics legacy options \"--showTopics\" and the current \"-T\" or \"--show-topics\" is used. Please only use \"-T\" or \"--show-topics\" as the legacy options will be removed in a future version.");
}
this.showTopics = showTopics;
}

@SuppressWarnings("unused")
@Deprecated(since = "4.34.0", forRemoval = true)
@CommandLine.Option(names = {"--showTopics"},
hidden = true,
description = "Option \"--showTopics\" is legacy, please use \"-T\" or \"--show-topics\". The legacy option will be removed in a future version")
private void showTopicsLegacy(final boolean showTopicsLegacy) {
deprecationWarnings.add(
"Option \"--showTopics\" is legacy, please use \"-T\" or \"--show-topics\". The legacy option will be removed in a future version.");

if (this.showTopics) {
throw new CommandLine.ParameterException(spec.commandLine(),
"A mix of the show topics legacy options \"--showTopics\" and the current \"-T\" or \"--show-topics\" is used. Please only use \"-T\" or \"--show-topics\" as the legacy options will be removed in a future version.");
}
showTopics = true;
}

private boolean printToSTDOUT = false;

public SubscribeOptions() {
public SubscribeOptions(final @NotNull List<String> deprecationWarnings) {
this.deprecationWarnings = deprecationWarnings;
setDefaultOptions();
}

Expand All @@ -98,8 +232,8 @@ public boolean isPrintToSTDOUT() {
return printToSTDOUT;
}

public boolean isBase64() {
return base64;
public boolean isEncodePayloadInBase64() {
return isEncodePayloadInBase64;
}

public boolean isJsonOutput() {
Expand Down Expand Up @@ -180,8 +314,7 @@ public void setDefaultOptions() {
outputFile +
", printToSTDOUT=" +
printToSTDOUT +
", base64=" +
base64 +
", base64=" + isEncodePayloadInBase64 +
", jsonOutput=" +
jsonOutput +
", showTopics=" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import picocli.CommandLine;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Scanner;
import java.util.concurrent.Callable;
Expand All @@ -40,6 +42,8 @@ public class ContextSubscribeCommand extends ShellContextCommand implements Call

private static final int IDLE_TIME = 1000;

private final @NotNull List<String> deprecationWarnings = new ArrayList<>();

@SuppressWarnings("unused")
@CommandLine.Option(names = {"-s", "--stay"},
defaultValue = "false",
Expand All @@ -55,7 +59,7 @@ private void printToSTDOUT(final boolean printToSTDOUT) {
}

@CommandLine.Mixin
private final @NotNull SubscribeOptions subscribeOptions = new SubscribeOptions();
private final @NotNull SubscribeOptions subscribeOptions = new SubscribeOptions(deprecationWarnings);

@Inject
public ContextSubscribeCommand(final @NotNull MqttClientExecutor mqttClientExecutor) {
Expand All @@ -66,6 +70,8 @@ public ContextSubscribeCommand(final @NotNull MqttClientExecutor mqttClientExecu
public @NotNull Integer call() {
Logger.trace("Command {}", this);

LoggerUtils.logDeprecatedOptions(deprecationWarnings);

if (contextClient == null) {
Logger.error("The client to subscribe with does not exist");
return 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class SubscribeMqtt3PublishCallback implements Consumer<Mqtt3Publish> {
SubscribeMqtt3PublishCallback(final @NotNull SubscribeOptions subscribeOptions, final @NotNull Mqtt3Client client) {
printToStdout = subscribeOptions.isPrintToSTDOUT();
outputFile = subscribeOptions.getOutputFile();
isBase64 = subscribeOptions.isBase64();
isBase64 = subscribeOptions.isEncodePayloadInBase64();
isJsonOutput = subscribeOptions.isJsonOutput();
showTopics = subscribeOptions.isShowTopics();
this.client = client;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class SubscribeMqtt5PublishCallback implements Consumer<Mqtt5Publish> {
SubscribeMqtt5PublishCallback(final @NotNull SubscribeOptions subscribeOptions, final @NotNull Mqtt5Client client) {
printToStdout = subscribeOptions.isPrintToSTDOUT();
outputFile = subscribeOptions.getOutputFile();
isBase64 = subscribeOptions.isBase64();
isBase64 = subscribeOptions.isEncodePayloadInBase64();
isJsonOutput = subscribeOptions.isJsonOutput();
showTopics = subscribeOptions.isShowTopics();
this.client = client;
Expand Down
Loading

0 comments on commit cd86b31

Please sign in to comment.