Fix Matter command argument list mismatch error (#23721)
* Fix Matter command argument list mismatch error
* Address the review comments
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java
index 559c244..c9d911b 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java
@@ -33,59 +33,78 @@
private final long mMax;
private final Object mValue;
private final Optional<String> mDesc;
+ private final boolean mOptional;
- public Argument(String name, IPAddress value) {
+ boolean isOptional() {
+ return mOptional;
+ }
+
+ public Argument(String name, IPAddress value, boolean optional) {
this.mName = name;
this.mType = ArgumentType.ADDRESS;
this.mMin = 0;
this.mMax = 0;
this.mValue = value;
this.mDesc = Optional.empty();
+ this.mOptional = optional;
}
- public Argument(String name, StringBuffer value, @Nullable String desc) {
+ public Argument(String name, StringBuffer value, @Nullable String desc, boolean optional) {
this.mName = name;
this.mType = ArgumentType.STRING;
this.mMin = 0;
this.mMax = 0;
this.mValue = value;
this.mDesc = Optional.ofNullable(desc);
+ this.mOptional = optional;
}
- public Argument(String name, AtomicBoolean value, @Nullable String desc) {
+ public Argument(String name, AtomicBoolean value, @Nullable String desc, boolean optional) {
this.mName = name;
this.mType = ArgumentType.BOOL;
this.mMin = 0;
this.mMax = 0;
this.mValue = value;
this.mDesc = Optional.ofNullable(desc);
+ this.mOptional = optional;
}
- public Argument(String name, short min, short max, AtomicInteger value, @Nullable String desc) {
+ public Argument(
+ String name,
+ short min,
+ short max,
+ AtomicInteger value,
+ @Nullable String desc,
+ boolean optional) {
this.mName = name;
this.mType = ArgumentType.NUMBER_INT16;
this.mMin = min;
this.mMax = max;
this.mValue = value;
this.mDesc = Optional.ofNullable(desc);
+ this.mOptional = optional;
}
- public Argument(String name, int min, int max, AtomicInteger value, @Nullable String desc) {
+ public Argument(
+ String name, int min, int max, AtomicInteger value, @Nullable String desc, boolean optional) {
this.mName = name;
this.mType = ArgumentType.NUMBER_INT32;
this.mMin = min;
this.mMax = max;
this.mValue = value;
this.mDesc = Optional.ofNullable(desc);
+ this.mOptional = optional;
}
- public Argument(String name, long min, long max, AtomicLong value, @Nullable String desc) {
+ public Argument(
+ String name, long min, long max, AtomicLong value, @Nullable String desc, boolean optional) {
this.mName = name;
this.mType = ArgumentType.NUMBER_INT64;
this.mMin = min;
this.mMax = max;
this.mValue = value;
this.mDesc = Optional.ofNullable(desc);
+ this.mOptional = optional;
}
public String getName() {
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Command.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Command.java
index 13ed473..16c3b30 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Command.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Command.java
@@ -32,6 +32,8 @@
* Matter devices from the environment.
*/
public abstract class Command {
+ private static final String OPTIONAL_ARGUMENT_PREFIX = "--";
+ private static final int OPTIONAL_ARGUMENT_PREFIX_LENGTH = 2;
private final String mName;
private final ArrayList<Argument> mArgs = new ArrayList<Argument>();
private final Optional<String> mHelpText;
@@ -82,17 +84,35 @@
return mArgs.get(index).getDesc();
}
+ public final void addArgumentToList(Argument arg, boolean optional) {
+ if (arg.isOptional() || mArgs.isEmpty()) {
+ // Safe to just append to the end of a list.
+ mArgs.add(arg);
+ return;
+ }
+
+ // mandatory arg needs to be inserted before the optional arguments.
+ int index = 0;
+ while (index < mArgs.size() && !mArgs.get(index).isOptional()) {
+ index++;
+ }
+
+ // Insert before the first optional arg.
+ mArgs.add(index, arg);
+ }
+
/**
* @brief Add a bool command argument
* @param name The name that will be displayed in the command help
* @param out A pointer to a MutableInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
+ * @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
*/
- public final int addArgument(String name, AtomicBoolean out, @Nullable String desc) {
- Argument arg = new Argument(name, out, desc);
- mArgs.add(arg);
- return mArgs.size();
+ public final void addArgument(
+ String name, AtomicBoolean out, @Nullable String desc, boolean optional) {
+ Argument arg = new Argument(name, out, desc, optional);
+ addArgumentToList(arg, optional);
}
/**
@@ -102,13 +122,18 @@
* @param max The minimum value of the argv value
* @param out A pointer to a MutableInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
+ * @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
*/
- public final int addArgument(
- String name, short min, short max, AtomicInteger out, @Nullable String desc) {
- Argument arg = new Argument(name, min, max, out, desc);
- mArgs.add(arg);
- return mArgs.size();
+ public final void addArgument(
+ String name,
+ short min,
+ short max,
+ AtomicInteger out,
+ @Nullable String desc,
+ boolean optional) {
+ Argument arg = new Argument(name, min, max, out, desc, optional);
+ addArgumentToList(arg, optional);
}
/**
@@ -118,13 +143,13 @@
* @param max The minimum value of the argv value
* @param out A pointer to a MutableInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
+ * @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
*/
- public final int addArgument(
- String name, int min, int max, AtomicInteger out, @Nullable String desc) {
- Argument arg = new Argument(name, min, max, out, desc);
- mArgs.add(arg);
- return mArgs.size();
+ public final void addArgument(
+ String name, int min, int max, AtomicInteger out, @Nullable String desc, boolean optional) {
+ Argument arg = new Argument(name, min, max, out, desc, optional);
+ addArgumentToList(arg, optional);
}
/**
@@ -134,25 +159,25 @@
* @param max The minimum value of the argv value
* @param out A pointer to a MutableInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
+ * @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
*/
- public final int addArgument(
- String name, long min, long max, AtomicLong out, @Nullable String desc) {
- Argument arg = new Argument(name, min, max, out, desc);
- mArgs.add(arg);
- return mArgs.size();
+ public final void addArgument(
+ String name, long min, long max, AtomicLong out, @Nullable String desc, boolean optional) {
+ Argument arg = new Argument(name, min, max, out, desc, optional);
+ addArgumentToList(arg, optional);
}
/**
* @brief Add an IP address command argument
* @param name The name that will be displayed in the command help
* @param out A pointer to a IPAddress where the argv value will be stored
+ * @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
*/
- public final int addArgument(String name, IPAddress out) {
- Argument arg = new Argument(name, out);
- mArgs.add(arg);
- return mArgs.size();
+ public final void addArgument(String name, IPAddress out, boolean optional) {
+ Argument arg = new Argument(name, out, optional);
+ addArgumentToList(arg, optional);
}
/**
@@ -160,12 +185,13 @@
* @param name The name that will be displayed in the command help
* @param out A pointer to a StringBuffer where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
+ * @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
*/
- public final int addArgument(String name, StringBuffer out, @Nullable String desc) {
- Argument arg = new Argument(name, out, desc);
- mArgs.add(arg);
- return mArgs.size();
+ public final void addArgument(
+ String name, StringBuffer out, @Nullable String desc, boolean optional) {
+ Argument arg = new Argument(name, out, desc, optional);
+ addArgumentToList(arg, optional);
}
/**
@@ -174,15 +200,44 @@
* @param args Supplied command-line arguments as an array of String objects.
*/
public final void initArguments(int argc, String[] args) {
- int argsCount = mArgs.size();
+ int mandatoryArgsCount = 0;
+ int currentIndex = 0;
- if (argsCount != argc) {
- throw new IllegalArgumentException(
- "Wrong arguments number: " + argc + " instead of " + argsCount);
+ for (Argument arg : mArgs) {
+ if (!arg.isOptional()) {
+ mandatoryArgsCount++;
+ }
}
- for (int i = 0; i < argsCount; i++) {
- initArgument(i, args[i]);
+ if (argc < mandatoryArgsCount) {
+ throw new IllegalArgumentException(
+ "initArguments: Wrong arguments number: " + argc + " instead of " + mandatoryArgsCount);
+ }
+
+ // Initialize mandatory arguments
+ for (int i = 0; i < mandatoryArgsCount; i++) {
+ initArgument(currentIndex++, args[i]);
+ }
+
+ // Initialize optional arguments
+ // Optional arguments expect a name and a value, so i is increased by 2 on every step.
+ for (int i = mandatoryArgsCount; i < argc; i += 2) {
+ // optional arguments starts with OPTIONAL_ARGUMENT_PREFIX
+ if (args[i].length() <= OPTIONAL_ARGUMENT_PREFIX_LENGTH
+ && !args[i].startsWith(OPTIONAL_ARGUMENT_PREFIX)) {
+ throw new IllegalArgumentException("initArguments: Invalid optional argument: " + args[i]);
+ }
+
+ if (args[i]
+ .substring(OPTIONAL_ARGUMENT_PREFIX_LENGTH)
+ .equals(mArgs.get(currentIndex).getName())) {
+ if (i + 1 >= argc) {
+ throw new IllegalArgumentException(
+ "initArguments: Optional argument " + args[i] + " missing value");
+ }
+
+ initArgument(currentIndex++, args[i + 1]);
+ }
}
}
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java
index 9aefec5..d78a7bb 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java
@@ -57,40 +57,43 @@
this.mCredIssuerCmds = Optional.ofNullable(credIssuerCmds);
this.mChipDeviceController = controller;
- // TODO: Add support to enable the below optional arguments
- /*
addArgument(
- "paa-trust-store-path",
+ "--paa-trust-store-path",
mPaaTrustStorePath,
"Path to directory holding PAA certificate information. Can be absolute or relative to the current working "
- + "directory.");
+ + "directory.",
+ true);
addArgument(
- "cd-trust-store-path",
+ "--cd-trust-store-path",
mCDTrustStorePath,
"Path to directory holding CD certificate information. Can be absolute or relative to the current working "
- + "directory.");
+ + "directory.",
+ true);
addArgument(
- "commissioner-name",
+ "--commissioner-name",
mCommissionerName,
"Name of fabric to use. Valid values are \"alpha\", \"beta\", \"gamma\", and integers greater than or equal to "
- + "4. The default if not specified is \"alpha\".");
+ + "4. The default if not specified is \"alpha\".",
+ true);
addArgument(
- "commissioner-nodeid",
+ "--commissioner-nodeid",
0,
Long.MAX_VALUE,
mCommissionerNodeId,
- "The node id to use for chip-tool. If not provided, kTestControllerNodeId (112233, 0x1B669) will be used.");
+ "The node id to use for chip-tool. If not provided, kTestControllerNodeId (112233, 0x1B669) will be used.",
+ true);
addArgument(
- "use-max-sized-certs",
+ "--use-max-sized-certs",
mUseMaxSizedCerts,
"Maximize the size of operational certificates. If not provided or 0 (\"false\"), normally sized operational "
- + "certificates are generated.");
+ + "certificates are generated.",
+ true);
addArgument(
- "only-allow-trusted-cd-keys",
+ "--only-allow-trusted-cd-keys",
mOnlyAllowTrustedCdKeys,
"Only allow trusted CD verifying keys (disallow test keys). If not provided or 0 (\"false\"), untrusted CD "
- + "verifying keys are allowed. If 1 (\"true\"), test keys are disallowed.");
- */
+ + "verifying keys are allowed. If 1 (\"true\"), test keys are disallowed.",
+ true);
}
// This method returns the commissioner instance to be used for running the command.
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/discover/DiscoverCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/discover/DiscoverCommand.java
index 3d0bf25..988e97b 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/discover/DiscoverCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/discover/DiscoverCommand.java
@@ -29,8 +29,8 @@
public DiscoverCommand(ChipDeviceController controller, CredentialsIssuer credsIssuer) {
super(controller, "resolve", credsIssuer);
- addArgument("nodeid", 0, Long.MAX_VALUE, mNodeId, null);
- addArgument("fabricid", 0, Long.MAX_VALUE, mFabricId, null);
+ addArgument("nodeid", 0, Long.MAX_VALUE, mNodeId, null, false);
+ addArgument("fabricid", 0, Long.MAX_VALUE, mFabricId, null, false);
}
@Override
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/CloseSessionCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/CloseSessionCommand.java
index ce3e263..f8b9112 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/CloseSessionCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/CloseSessionCommand.java
@@ -30,13 +30,14 @@
public CloseSessionCommand(ChipDeviceController controller, CredentialsIssuer credsIssuer) {
super(controller, "close-session", credsIssuer);
- addArgument("destination-id", 0, Long.MAX_VALUE, mDestinationId, null);
+ addArgument("destination-id", 0, Long.MAX_VALUE, mDestinationId, null, false);
addArgument(
"timeout",
(short) 0,
Short.MAX_VALUE,
mTimeoutSecs,
- "Time, in seconds, before this command is considered to have timed out.");
+ "Time, in seconds, before this command is considered to have timed out.",
+ false);
}
@Override
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java
index 323c3bd..2d4a6bb 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java
@@ -163,18 +163,18 @@
throw new RuntimeException(e);
}
- addArgument("node-id", 0, Long.MAX_VALUE, mNodeId, null);
+ addArgument("node-id", 0, Long.MAX_VALUE, mNodeId, null, false);
switch (networkType) {
case NONE:
case ETHERNET:
break;
case WIFI:
- addArgument("ssid", mSSID, null);
- addArgument("password", mPassword, null);
+ addArgument("ssid", mSSID, null, false);
+ addArgument("password", mPassword, null, false);
break;
case THREAD:
- addArgument("operationalDataset", mOperationalDataset, null);
+ addArgument("operationalDataset", mOperationalDataset, null, false);
break;
}
@@ -184,29 +184,29 @@
case CODE:
case CODE_PASE_ONLY:
Only:
- addArgument("payload", mOnboardingPayload, null);
- addArgument("discover-once", mDiscoverOnce, null);
- addArgument("use-only-onnetwork-discovery", mUseOnlyOnNetworkDiscovery, null);
+ addArgument("payload", mOnboardingPayload, null, false);
+ addArgument("discover-once", mDiscoverOnce, null, false);
+ addArgument("use-only-onnetwork-discovery", mUseOnlyOnNetworkDiscovery, null, false);
break;
case BLE:
- addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null);
- addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null);
+ addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null, false);
+ addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null, false);
break;
case ON_NETWORK:
- addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null);
+ addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null, false);
break;
case SOFT_AP:
AP:
- addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null);
- addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null);
- addArgument("device-remote-ip", mRemoteAddr);
- addArgument("device-remote-port", (short) 0, Short.MAX_VALUE, mRemotePort, null);
+ addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null, false);
+ addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null, false);
+ addArgument("device-remote-ip", mRemoteAddr, false);
+ addArgument("device-remote-port", (short) 0, Short.MAX_VALUE, mRemotePort, null, false);
break;
case ETHERNET:
- addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null);
- addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null);
- addArgument("device-remote-ip", mRemoteAddr);
- addArgument("device-remote-port", (short) 0, Short.MAX_VALUE, mRemotePort, null);
+ addArgument("setup-pin-code", 0, 134217727, mSetupPINCode, null, false);
+ addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null, false);
+ addArgument("device-remote-ip", mRemoteAddr, false);
+ addArgument("device-remote-port", (short) 0, Short.MAX_VALUE, mRemotePort, null, false);
break;
}
@@ -214,28 +214,28 @@
case NONE:
break;
case SHORT_DISCRIMINATOR:
- addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null);
+ addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null, false);
break;
case LONG_DISCRIMINATOR:
- addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null);
+ addArgument("discriminator", (short) 0, (short) 4096, mDiscriminator, null, false);
break;
case VENDOR_ID:
- addArgument("vendor-id", (short) 0, Short.MAX_VALUE, mDiscoveryFilterCode, null);
+ addArgument("vendor-id", (short) 0, Short.MAX_VALUE, mDiscoveryFilterCode, null, false);
break;
case COMPRESSED_FABRIC_ID:
- addArgument("fabric-id", 0, Long.MAX_VALUE, mDiscoveryFilterCode, null);
+ addArgument("fabric-id", 0, Long.MAX_VALUE, mDiscoveryFilterCode, null, false);
break;
case COMMISSIONING_MODE:
case COMMISSIONER:
break;
case DEVICE_TYPE:
- addArgument("device-type", (short) 0, Short.MAX_VALUE, mDiscoveryFilterCode, null);
+ addArgument("device-type", (short) 0, Short.MAX_VALUE, mDiscoveryFilterCode, null, false);
break;
case INSTANCE_NAME:
- addArgument("name", mDiscoveryFilterInstanceName, null);
+ addArgument("name", mDiscoveryFilterInstanceName, null, false);
break;
}
- addArgument("timeout", (long) 0, Long.MAX_VALUE, mTimeoutMillis, null);
+ addArgument("timeout", (long) 0, Long.MAX_VALUE, mTimeoutMillis, null, false);
}
}