+ *
+ * @param index the index of the bit to be returned.
+ * @return true if the bit at the specified index is set,
+ * false otherwise.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ public boolean getBit(int index) {
+ if (index >= size()) {
+ throw new IndexOutOfBoundsException();
+ }
+ return this.wrapped.get(index);
+ }
+
+ public void setBit(int index, boolean value) {
+ if (value) {
+ this.wrapped.set(index);
+ } else {
+ this.wrapped.clear(index);
+ }
+ }
+
+ /**
+ * Get number of bits stored in this instance
+ *
+ * @return
+ */
+ public int size() {
+ return length;
+ }
+
+ @Override
+ public String toString() {
+ return "BitArray(bits=" + (length == 0 ? "
+ *
+ * @return the subnet identifier as int.
+ */
+ public int getSubnetID() {
+ return slaveId;
+ }
+
+ /**
+ * Returns the unit identifier of this
+ * ModbusMessage as int.
+ *
+ * @return the unit identifier as int.
+ */
+ public int getUnitID() {
+ return slaveId;
+ }
+
+ public int getReference() {
+ return start;
+ }
+
+ public ModbusReadFunctionCode getFunctionCode() {
+ return functionCode;
+ }
+
+ public int getDataLength() {
+ return length;
+ }
+
+ /**
+ * Maximum number of tries to execute the request, when request fails
+ *
+ * For example, number 1 means on try only with no re-tries.
+ *
+ * @return number of maximum tries
+ */
+ public int getMaxTries() {
+ return maxTries;
+ }
+
+ /**
+ * Returns the protocol identifier of this
+ * ModbusMessage as int.
+ *
+ * @return the protocol identifier as int.
+ */
+ public int getProtocolID() {
+ return Modbus.DEFAULT_PROTOCOL_ID;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(functionCode, length, maxTries, slaveId, start);
+ }
+
+ @Override
+ public String toString() {
+ return "ModbusReadRequestBlueprint [slaveId=" + slaveId + ", functionCode=" + functionCode + ", start=" + start
+ + ", length=" + length + ", maxTries=" + maxTries + "]";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ ModbusReadRequestBlueprint rhs = (ModbusReadRequestBlueprint) obj;
+ return functionCode == rhs.functionCode && length == rhs.length && slaveId == rhs.slaveId && start == rhs.start;
+ }
+}
diff --git a/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusRegisterArray.java b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusRegisterArray.java
new file mode 100644
index 00000000000..8ceb16e339f
--- /dev/null
+++ b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusRegisterArray.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.io.transport.sbus;
+
+import java.util.Arrays;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.util.HexUtils;
+
+/**
+ * Immutable {@link ModbusRegisterArray} implementation
+ *
+ * @author Sami Salonen - Initial contribution
+ */
+@NonNullByDefault
+public class ModbusRegisterArray {
+
+ private final byte[] bytes;
+
+ public ModbusRegisterArray(byte... bytes) {
+ if (bytes.length % 2 != 0) {
+ throw new IllegalArgumentException();
+ }
+ this.bytes = Arrays.copyOf(bytes, bytes.length);
+ }
+
+ /**
+ * Construct plain
+ *
+ * @return the protocol identifier as int.
+ */
+ public int getProtocolID() {
+ return Modbus.DEFAULT_PROTOCOL_ID;
+ }
+
+ /**
+ * Returns the reference of the register/coil/discrete input to to start
+ * writing with this request
+ *
+ *
+ * @return the reference of the register
+ * to start reading from as int.
+ */
+ public abstract int getReference();
+
+ /**
+ * Returns the subnet identifier of this
+ * ModbusMessage as int.
+ *
+ * @return the unit identifier as int.
+ */
+ public abstract int getSubnetID();
+
+ /**
+ * Returns the unit identifier of this
+ * ModbusMessage as int.
+ *
+ * @return the unit identifier as int.
+ */
+ public abstract int getUnitID();
+
+ /**
+ * Returns the function code of this
+ * ModbusMessage as int.
+ *
+ * @return the function code as int.
+ *
+ * @see ro.ciprianpascu.sbus.Modbus
+ */
+ public abstract ModbusWriteFunctionCode getFunctionCode();
+
+ /**
+ * Get maximum number of tries, in case errors occur. Should be at least 1.
+ */
+ public abstract int getMaxTries();
+
+ /**
+ * Accept visitor
+ *
+ * @param visitor
+ */
+ public abstract void accept(ModbusWriteRequestBlueprintVisitor visitor);
+}
diff --git a/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRequestBlueprintVisitor.java b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRequestBlueprintVisitor.java
new file mode 100644
index 00000000000..a874f4e66cc
--- /dev/null
+++ b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRequestBlueprintVisitor.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.io.transport.sbus;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ *
+ * ModbusWriteRequestBlueprintVisitor interface.
+ *
+ * The identifier is a 1-byte non negative
+ * integer value valid in the range of 0-255.
+ *
+ * The identifier is a 1-byte non negative
+ * integer value valid in the range of 0-255.
+ *
+ * The identifier is a 2-byte (short) non negative
+ * integer value valid in the range of 0-65535.
+ * ModbusRegisterArray
array from register values
+ *
+ * @param registerValues register values, each int
corresponding to one register
+ */
+ public ModbusRegisterArray(int... registerValues) {
+ bytes = new byte[registerValues.length * 2];
+ for (int registerIndex = 0; registerIndex < registerValues.length; registerIndex++) {
+ int register = registerValues[registerIndex] & 0xffff;
+ // hi-byte
+ bytes[registerIndex * 2] = (byte) (register >> 8);
+ // lo byte
+ bytes[registerIndex * 2 + 1] = (byte) register;
+ }
+ }
+
+ /**
+ * Get register index i as unsigned integer
+ *
+ * @param i register index
+ * @return register value interpreted as unsigned integer (big-endian byte ordering)
+ */
+ public int getRegister(int i) {
+ int hi = bytes[i * 2] & 0xff;
+ int lo = bytes[i * 2 + 1] & 0xff;
+ return ((hi << 8) | lo) & 0xffff;
+ }
+
+ /**
+ * Return bytes representing the registers
+ *
+ *
+ * Index 0: hi-byte of 1st register
+ * Index 1: low-byte of 1st register
+ * Index 3: hi-byte of 2nd register
+ * Index 4: low-byte of 2nd register
+ * ...
+ *
+ * @return set of bytes
+ */
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ /**
+ * Get number of registers stored in this instance
+ *
+ * @return
+ */
+ public int size() {
+ return bytes.length / 2;
+ }
+
+ @Override
+ public String toString() {
+ if (bytes.length == 0) {
+ return "ModbusRegisterArray(data
is empty, writeMultiple
is
+ * false
but there are many bits to write.
+ */
+ public ModbusWriteCoilRequestBlueprint(int subnetId, int slaveId, int reference, BitArray data,
+ boolean writeMultiple, int maxTries) {
+ super();
+ this.subnetId = subnetId;
+ this.slaveId = slaveId;
+ this.reference = reference;
+ this.bits = data;
+ this.writeMultiple = writeMultiple;
+ this.maxTries = maxTries;
+
+ if (!writeMultiple && bits.size() > 1) {
+ throw new IllegalArgumentException("With multiple coils, writeMultiple must be true");
+ }
+ if (bits.size() == 0) {
+ throw new IllegalArgumentException("Must have at least one bit");
+ }
+ if (maxTries <= 0) {
+ throw new IllegalArgumentException("maxTries should be positive, was " + maxTries);
+ }
+ }
+
+ @Override
+ public int getSubnetID() {
+ return subnetId;
+ }
+
+ @Override
+ public int getUnitID() {
+ return slaveId;
+ }
+
+ @Override
+ public int getReference() {
+ return reference;
+ }
+
+ @Override
+ public ModbusWriteFunctionCode getFunctionCode() {
+ return writeMultiple ? ModbusWriteFunctionCode.WRITE_MULTIPLE_COILS : ModbusWriteFunctionCode.WRITE_COIL;
+ }
+
+ public BitArray getCoils() {
+ return bits;
+ }
+
+ @Override
+ public int getMaxTries() {
+ return maxTries;
+ }
+
+ @Override
+ public String toString() {
+ return "ModbusWriteCoilRequestBlueprint [slaveId=" + slaveId + ", reference=" + reference + ", bits=" + bits
+ + ", maxTries=" + maxTries + ", getFunctionCode()=" + getFunctionCode() + "]";
+ }
+
+ @Override
+ public void accept(ModbusWriteRequestBlueprintVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteFunctionCode.java b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteFunctionCode.java
new file mode 100644
index 00000000000..5c4f5106dae
--- /dev/null
+++ b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteFunctionCode.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.io.transport.sbus;
+
+import java.util.stream.Stream;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import ro.ciprianpascu.sbus.Modbus;
+
+/**
+ * Modbus write function codes supported by this transport
+ *
+ * @author Sami Salonen - Initial contribution
+ */
+@NonNullByDefault
+public enum ModbusWriteFunctionCode {
+ WRITE_COIL(Modbus.WRITE_COIL),
+ WRITE_MULTIPLE_COILS(Modbus.WRITE_MULTIPLE_COILS),
+ WRITE_SINGLE_REGISTER(Modbus.WRITE_SINGLE_REGISTER),
+ WRITE_MULTIPLE_REGISTERS(Modbus.WRITE_MULTIPLE_REGISTERS);
+
+ private final int functionCode;
+
+ ModbusWriteFunctionCode(int code) {
+ functionCode = code;
+ }
+
+ /**
+ * Get numeric function code represented by this instance
+ *
+ * @return
+ */
+ public int getFunctionCode() {
+ return functionCode;
+ }
+
+ /**
+ * Construct {@link ModbusWriteFunctionCode} from the numeric function code
+ *
+ * @param functionCode numeric function code
+ * @return {@link ModbusWriteFunctionCode} matching the numeric function code
+ * @throws IllegalArgumentException with unsupported functions
+ */
+ public static ModbusWriteFunctionCode fromFunctionCode(int functionCode) throws IllegalArgumentException {
+ return Stream.of(ModbusWriteFunctionCode.values()).filter(v -> v.getFunctionCode() == functionCode).findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("Invalid functionCode"));
+ }
+}
diff --git a/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRegisterRequestBlueprint.java b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRegisterRequestBlueprint.java
new file mode 100644
index 00000000000..e408ab6a80c
--- /dev/null
+++ b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRegisterRequestBlueprint.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.io.transport.sbus;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Implementation for writing registers
+ *
+ * @author Sami Salonen - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class ModbusWriteRegisterRequestBlueprint extends ModbusWriteRequestBlueprint {
+
+ private final int subnetId;
+ private final int slaveId;
+ private final int reference;
+ private final ModbusRegisterArray registers;
+ private final boolean writeMultiple;
+ private final int maxTries;
+
+ /**
+ * Construct coil write request with many bits of data
+ *
+ * @param slaveId slave id to write to
+ * @param reference reference address
+ * @param registers register(s) to write
+ * @param writeMultiple whether to use {@link ModbusWriteFunctionCode#WRITE_MULTIPLE_COILS} over
+ * {@link ModbusWriteFunctionCode#WRITE_COIL}. Useful with single register of data.
+ * @param maxTries maximum number of tries in case of errors, should be at least 1
+ * @throws IllegalArgumentException in case data
is empty, writeMultiple
is
+ * false
but there are many registers to write.
+ */
+ public ModbusWriteRegisterRequestBlueprint(int subnetId, int slaveId, int reference, ModbusRegisterArray registers,
+ boolean writeMultiple, int maxTries) throws IllegalArgumentException {
+ super();
+ this.subnetId = subnetId;
+ this.slaveId = slaveId;
+ this.reference = reference;
+ this.registers = registers;
+ this.writeMultiple = writeMultiple;
+ this.maxTries = maxTries;
+
+ if (!writeMultiple && registers.size() > 1) {
+ throw new IllegalArgumentException("With multiple registers, writeMultiple must be true");
+ }
+ if (registers.size() == 0) {
+ throw new IllegalArgumentException("Must have at least one register");
+ }
+ if (maxTries <= 0) {
+ throw new IllegalArgumentException("maxTries should be positive");
+ }
+ }
+
+ @Override
+ public int getReference() {
+ return reference;
+ }
+
+ @Override
+ public int getSubnetID() {
+ return subnetId;
+ }
+
+ @Override
+ public int getUnitID() {
+ return slaveId;
+ }
+
+ @Override
+ public ModbusWriteFunctionCode getFunctionCode() {
+ return writeMultiple ? ModbusWriteFunctionCode.WRITE_MULTIPLE_REGISTERS
+ : ModbusWriteFunctionCode.WRITE_SINGLE_REGISTER;
+ }
+
+ public ModbusRegisterArray getRegisters() {
+ return registers;
+ }
+
+ @Override
+ public int getMaxTries() {
+ return maxTries;
+ }
+
+ @Override
+ public String toString() {
+ return "ModbusWriteRegisterRequestBlueprint [slaveId=" + slaveId + ", reference=" + reference + ", registers="
+ + registers + ", maxTries=" + maxTries + ", getFunctionCode()=" + getFunctionCode() + "]";
+ }
+
+ @Override
+ public void accept(ModbusWriteRequestBlueprintVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRequestBlueprint.java b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRequestBlueprint.java
new file mode 100644
index 00000000000..6ab8543f8f7
--- /dev/null
+++ b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/ModbusWriteRequestBlueprint.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.io.transport.sbus;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import ro.ciprianpascu.sbus.Modbus;
+
+/**
+ * Base interface for Modbus write requests
+ *
+ * @author Sami Salonen - Initial contribution
+ *
+ */
+@NonNullByDefault
+public abstract class ModbusWriteRequestBlueprint {
+
+ /**
+ * Returns the protocol identifier of this
+ * ModbusMessage as int.
+ * The identifier is a 2-byte (short) non negative
+ * integer value valid in the range of 0-65535.
+ *
+ * The identifier is a 1-byte non negative
+ * integer value valid in the range of 0-255.
+ *
+ * The identifier is a 1-byte non negative
+ * integer value valid in the range of 0-255.
+ *
+ * The function code is a 1-byte non negative
+ * integer value valid in the range of 0-127.
+ * Function codes are ordered in conformance
+ * classes their values are specified in
+ * ro.ciprianpascu.sbus.Modbus.
+ * waitMillis
has passed from lastOperation
+ *
+ * @param lastOperation last time operation was executed, or null if it has not been executed
+ * @param waitMillis
+ * @return milliseconds slept
+ * @throws InterruptedException
+ */
+ public static long waitAtleast(@Nullable Long lastOperation, long waitMillis) throws InterruptedException {
+ if (lastOperation == null) {
+ return 0;
+ }
+ long millisSinceLast = System.currentTimeMillis() - lastOperation;
+ long millisToWaitStill = Math.min(waitMillis, Math.max(0, waitMillis - millisSinceLast));
+ try {
+ Thread.sleep(millisToWaitStill);
+ } catch (InterruptedException e) {
+ LoggerFactory.getLogger(ModbusSlaveConnectionFactoryImpl.class).debug("wait interrupted", e);
+ throw e;
+ }
+ return millisToWaitStill;
+ }
+
+ /**
+ * Disconnect returning connections which have been connected before certain time
+ *
+ * @param disconnectBeforeConnectedMillis disconnected connections that have been connected before this time
+ */
+ public void disconnectOnReturn(ModbusSlaveEndpoint endpoint, long disconnectBeforeConnectedMillis) {
+ disconnectIfConnectedBefore.put(endpoint, disconnectBeforeConnectedMillis);
+ }
+}
diff --git a/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/json/WriteRequestJsonUtilities.java b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/json/WriteRequestJsonUtilities.java
new file mode 100644
index 00000000000..f46620fbcee
--- /dev/null
+++ b/bundles/org.openhab.core.io.transport.sbus/src/main/java/org/openhab/core/io/transport/sbus/json/WriteRequestJsonUtilities.java
@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.core.io.transport.sbus.json;
+
+import java.util.Collection;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.io.transport.sbus.BitArray;
+import org.openhab.core.io.transport.sbus.ModbusConstants;
+import org.openhab.core.io.transport.sbus.ModbusRegisterArray;
+import org.openhab.core.io.transport.sbus.ModbusWriteCoilRequestBlueprint;
+import org.openhab.core.io.transport.sbus.ModbusWriteFunctionCode;
+import org.openhab.core.io.transport.sbus.ModbusWriteRegisterRequestBlueprint;
+import org.openhab.core.io.transport.sbus.ModbusWriteRequestBlueprint;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ * Utilities for converting JSON to {@link ModbusWriteRequestBlueprint}
+ *
+ *
+ * @author Sami Salonen - Initial contribution
+ */
+@NonNullByDefault
+public final class WriteRequestJsonUtilities {
+ /**
+ * Constant for the function code key in the JSON
+ */
+ public static final String JSON_FUNCTION_CODE = "functionCode";
+ /**
+ * Constant for the write address key in the JSON
+ */
+ public static final String JSON_ADDRESS = "address";
+ /**
+ * Constant for the value key in the JSON
+ */
+ public static final String JSON_VALUE = "value";
+ /**
+ * Constant for the maxTries key in the JSON
+ */
+ public static final String JSON_MAX_TRIES = "maxTries";
+
+ /**
+ * Default maxTries when it has not been specified
+ */
+ public static final int DEFAULT_MAX_TRIES = 3;
+
+ private WriteRequestJsonUtilities() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Parse JSON string to collection of {@link ModbusWriteRequestBlueprint}
+ *
+ * JSON string should represent a JSON array, with JSON objects. Each JSON object represents a write request. The
+ * JSON object must have the following keys
+ * - functionCode: numeric function code
+ * - address: reference or start address of the write
+ * - value: array of data to be written. Use zero and one when writing coils. With registers, each number
+ * corresponds to register's 16 bit data.
+ * - maxTries: number of tries with the write in case of errors
+ *
+ *
+ * @param unitId unit id for the constructed {@link ModbusWriteRequestBlueprint}
+ * @param jsonString json to be parsed in string format
+ * @return collection of {@link ModbusWriteRequestBlueprint} representing the json
+ * @throws IllegalArgumentException in case of unexpected function codes, or too large payload exceeding modbus
+ * protocol specification
+ * @throws IllegalStateException in case of parsing errors and unexpected json structure
+ *
+ * @see WriteRequestJsonUtilities#JSON_FUNCTION_CODE
+ * @see WriteRequestJsonUtilities#JSON_ADDRESS
+ * @see WriteRequestJsonUtilities#JSON_VALUE
+ * @see WriteRequestJsonUtilities#JSON_MAX_TRIES
+ */
+ public static Collection