io_nats_client_support - RichardHightower/jnats GitHub Wiki

io.nats.client.support

ServerVersion

ServerVersion

The ServerVersion class is a public class that implements the Comparable interface. It represents a server version and allows for comparisons between different server versions.

@Override

public int compareTo(ServerVersion o)

@Override
public int compareTo(ServerVersion o) {
    int c = major.compareTo(o.major);
    if (c == 0) {
        c = minor.compareTo(o.minor);
        if (c == 0) {
            c = patch.compareTo(o.patch);
            if (c == 0) {
                if (extra == null) {
                    c = o.extra == null ? 0 : 1;
                } else if (o.extra == null) {
                    c = -1;
                } else {
                    c = extra.compareTo(o.extra);
                }
            }
        }
    }
    return c;
}

The compareTo method in the ServerVersion class is used to compare two ServerVersion objects based on their properties such as major version, minor version, patch version, and extra information.

Here is a step-by-step description of what the compareTo method does:

  1. Compares the major property of the current ServerVersion object to the major property of the o object (passed as an argument to the method) using the compareTo method. The result is stored in the variable c.
  2. If c is equal to 0 (indicating that the major versions are equal), the method proceeds to compare the minor property of both objects using the compareTo method. The result is again stored in the variable c.
  3. If c is equal to 0 (indicating that the minor versions are equal), the method compares the patch property of both objects using the compareTo method. The result is again stored in the variable c.
  4. If c is equal to 0 (indicating that the patch versions are equal), the method checks if the extra property of the current object is null. If it is null, the method checks if the extra property of the o object is also null. If both are null, the method sets c to 0. Otherwise, it sets c to 1.
  5. If c is not equal to 0 (indicating that the extra strings are different), the method checks if the o.extra property is null. If it is null, the method sets c to -1. Otherwise, it proceeds to compare the extra property of both objects using the compareTo method.
  6. Finally, the method returns the value of c, which represents the result of the comparison.

In summary, the compareTo method compares two ServerVersion objects based on their major, minor, patch versions, and extra information. It returns 0 if the objects are equal, a positive integer if the current object is greater than the argument object, and a negative integer if the current object is less than the argument object.

The compareTo method in the ServerVersion class is used to compare two ServerVersion objects. It compares the major, minor, and patch versions of the two objects sequentially.

The method first compares the major versions of the two objects using the compareTo method of the major version. If the major versions are equal, it moves on to compare the minor versions. If the minor versions are also equal, it compares the patch versions.

If the patch versions are equal as well, it checks if the extra field of one object is null. If the extra field is null, it considers the other object as greater (returns 1). If the extra field of the other object is null, it considers the current object as greater (returns -1). If both extra fields are not null, it compares them using the compareTo method of the extra field.

Finally, the method returns the value of c, which represents the comparison result. A negative value indicates that the current object is less than the given object, a positive value indicates it is greater, and a zero value indicates they are equal.

sequence diagram

Status

Status

The Status class is a public class that represents the status of a certain process or entity. Its primary purpose is to provide information about the current state or condition of the process or entity it represents. With its various methods and attributes, the Status class allows software engineers to easily track and manage the status of different processes within their applications.

private static int extractCode(Token codeToken)

private static int extractCode(Token codeToken) {
    try {
        return Integer.parseInt(codeToken.getValue());
    } catch (Exception e) {
        throw new IllegalArgumentException(NatsConstants.INVALID_HEADER_STATUS_CODE);
    }
}

The extractCode method is used to extract an integer value from a Token object. The method takes a single parameter codeToken, which represents the token containing the code value.

Here is a step-by-step description of what the extractCode method is doing based on its body:

  1. The method is declared as private and static, indicating that it can only be accessed within the io.nats.client.support.Status class and does not require an instance of the class to be called.

  2. The method signature specifies that the return type of the method is int, indicating that the method will return an integer value.

  3. Within a try block, the method attempts to parse the value of the codeToken by calling the getValue method on it, and then converting the returned value to an integer using the Integer.parseInt method.

  4. If the parsing succeeds, the parsed integer value is returned as the result of the method.

  5. If an exception occurs during parsing, for example, if the value of the codeToken is not a valid integer, the method catches the exception.

  6. In the catch block, an IllegalArgumentException is thrown with the message NatsConstants.INVALID_HEADER_STATUS_CODE. This indicates that the code value could not be extracted due to an invalid format.

That's a step-by-step description of the extractCode method in the io.nats.client.support.Status class.

The method extractCode is a private static method defined in the class io.nats.client.support.Status.

It takes a parameter codeToken of type Token and returns an integer.

The purpose of this method is to extract the code value from the codeToken and convert it into an integer.

If an exception occurs during the conversion process, it throws an IllegalArgumentException with the message "Invalid header status code defined in NatsConstants class".

sequence diagram

JwtUtils

JwtUtils

The JwtUtils class is an abstract class that implements ADR-14.

public static String issueUserJWT(NKey signingKey, String publicUserKey, String name, Duration expiration, long issuedAt, UserClaim nats) throws GeneralSecurityException, IOException

public static String issueUserJWT(NKey signingKey, String publicUserKey, String name, Duration expiration, long issuedAt, UserClaim nats) throws GeneralSecurityException, IOException {
    // Validate the signingKey:
    if (signingKey.getType() != NKey.Type.ACCOUNT) {
        throw new IllegalArgumentException("issueUserJWT requires an account key for the signingKey parameter, but got " + signingKey.getType());
    }
    // Validate the accountId:
    NKey accountKey = NKey.fromPublicKey(nats.issuerAccount.toCharArray());
    if (accountKey.getType() != NKey.Type.ACCOUNT) {
        throw new IllegalArgumentException("issueUserJWT requires an account key for the accountId parameter, but got " + accountKey.getType());
    }
    // Validate the publicUserKey:
    NKey userKey = NKey.fromPublicKey(publicUserKey.toCharArray());
    if (userKey.getType() != NKey.Type.USER) {
        throw new IllegalArgumentException("issueUserJWT requires a user key for the publicUserKey, but got " + userKey.getType());
    }
    String accSigningKeyPub = new String(signingKey.getPublicKey());
    String claimName = Validator.nullOrEmpty(name) ? publicUserKey : name;
    return issueJWT(signingKey, publicUserKey, claimName, expiration, issuedAt, accSigningKeyPub, nats);
}

The issueUserJWT method is defined as follows:

public static String issueUserJWT(NKey signingKey, String publicUserKey, String name, Duration expiration, long issuedAt, UserClaim nats) throws GeneralSecurityException, IOException {
    // Validate the signingKey:
    if (signingKey.getType() != NKey.Type.ACCOUNT) {
        throw new IllegalArgumentException("issueUserJWT requires an account key for the signingKey parameter, but got " + signingKey.getType());
    }
    // Validate the accountId:
    NKey accountKey = NKey.fromPublicKey(nats.issuerAccount.toCharArray());
    if (accountKey.getType() != NKey.Type.ACCOUNT) {
        throw new IllegalArgumentException("issueUserJWT requires an account key for the accountId parameter, but got " + accountKey.getType());
    }
    // Validate the publicUserKey:
    NKey userKey = NKey.fromPublicKey(publicUserKey.toCharArray());
    if (userKey.getType() != NKey.Type.USER) {
        throw new IllegalArgumentException("issueUserJWT requires a user key for the publicUserKey, but got " + userKey.getType());
    }
    String accSigningKeyPub = new String(signingKey.getPublicKey());
    String claimName = Validator.nullOrEmpty(name) ? publicUserKey : name;
    return issueJWT(signingKey, publicUserKey, claimName, expiration, issuedAt, accSigningKeyPub, nats);
}

The steps carried out by this method, based on its body, are as follows:

  1. Validate the signingKey parameter to ensure that it is of type NKey.Type.ACCOUNT. If it is not, throw an IllegalArgumentException with a message indicating the incorrect type.

  2. Validate the accountId parameter by converting it to an NKey object using NKey.fromPublicKey. Ensure that the resulting key has a type of NKey.Type.ACCOUNT. If it does not, throw an IllegalArgumentException with a message indicating the incorrect type.

  3. Validate the publicUserKey parameter by converting it to an NKey object using NKey.fromPublicKey. Ensure that the resulting key has a type of NKey.Type.USER. If it does not, throw an IllegalArgumentException with a message indicating the incorrect type.

  4. Convert the signingKey's public key to a String using new String(signingKey.getPublicKey()).

  5. Set the claimName variable based on the value of the name parameter. If the name parameter is null or empty, use the value of publicUserKey as the claimName.

  6. Call the issueJWT method, passing in the signingKey, publicUserKey, claimName, expiration, issuedAt, accSigningKeyPub, and nats parameters.

  7. Return the result of the issueJWT method as the output of the issueUserJWT method.

Note: The issueJWT method is not included in the provided code snippet.

The issueUserJWT method in the JwtUtils class is responsible for generating a JSON Web Token (JWT) for a user.

Here's a breakdown of what the method does:

  1. It first validates the signingKey parameter to ensure that it is of type NKey.Type.ACCOUNT. If not, it throws an IllegalArgumentException.

  2. It then validates the accountId parameter by converting it to an NKey object and checking if it is of type NKey.Type.ACCOUNT. If not, it throws an IllegalArgumentException.

  3. Next, it validates the publicUserKey parameter by converting it to an NKey object and checking if it is of type NKey.Type.USER. If not, it throws an IllegalArgumentException.

  4. The method then generates the public key of the signing key as a string.

  5. It determines the claimName for the JWT by checking if the name parameter is null or empty. If so, it uses the publicUserKey as the claim name, otherwise it uses the name parameter.

  6. Finally, it calls the issueJWT method, passing in the necessary parameters, to issue the JWT and returns the generated token.

Note: The method may throw GeneralSecurityException or IOException if there are any issues during the JWT generation process.

sequence diagram

public static String issueJWT(NKey signingKey, String publicUserKey, String name, Duration expiration, long issuedAt, String accSigningKeyPub, JsonSerializable nats) throws GeneralSecurityException, IOException

public static String issueJWT(NKey signingKey, String publicUserKey, String name, Duration expiration, long issuedAt, String accSigningKeyPub, JsonSerializable nats) throws GeneralSecurityException, IOException {
    Claim claim = new Claim();
    claim.exp = expiration;
    claim.iat = issuedAt;
    claim.iss = accSigningKeyPub;
    claim.name = name;
    claim.sub = publicUserKey;
    claim.nats = nats;
    // Issue At time is stored in unix seconds
    String claimJson = claim.toJson();
    // Compute jti, a base32 encoded sha256 hash
    MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
    byte[] encoded = sha256.digest(claimJson.getBytes(StandardCharsets.UTF_8));
    claim.jti = new String(base32Encode(encoded));
    claimJson = claim.toJson();
    // all three components (header/body/signature) are base64url encoded
    String encBody = toBase64Url(claimJson);
    // compute the signature off of header + body (. included on purpose)
    byte[] sig = (ENCODED_CLAIM_HEADER + "." + encBody).getBytes(StandardCharsets.UTF_8);
    String encSig = toBase64Url(signingKey.sign(sig));
    // append signature to header and body and return it
    return ENCODED_CLAIM_HEADER + "." + encBody + "." + encSig;
}

Method Description - issueJWT

The issueJWT method, defined in the io.nats.client.support.JwtUtils class, is responsible for issuing a JSON Web Token (JWT) based on the provided parameters.

Method Signature

public static String issueJWT(NKey signingKey, String publicUserKey, String name, Duration expiration, long issuedAt, String accSigningKeyPub, JsonSerializable nats) throws GeneralSecurityException, IOException

Parameters

  • signingKey: NKey object representing the private key used for signing the JWT.
  • publicUserKey: String representing the public key of the user.
  • name: String representing the name associated with the JWT.
  • expiration: Duration object representing the time duration for which the JWT is valid.
  • issuedAt: long representing the timestamp when the JWT was issued.
  • accSigningKeyPub: String representing the public key of the account signing key.
  • nats: JsonSerializable object representing additional data associated with the JWT.

Return Value

The method returns a String representing the issued JWT.

Steps

The issueJWT method follows the following steps to issue the JWT:

  1. Create a new Claim object.
  2. Set the expiration, issuedAt, accSigningKeyPub, name, publicUserKey, and nats fields of the Claim object based on the provided parameters.
  3. Convert the Claim object to a JSON string using the toJson method and store it in the claimJson variable.
  4. Compute the SHA-256 hash of the claimJson string and encode it using base32 encoding. Set the result as the jti field of the Claim object.
  5. Convert the Claim object to JSON string again and update the claimJson variable with the updated JSON string.
  6. Encode the claimJson string using base64url encoding and store it in the encBody variable.
  7. Concatenate the ENCODED_CLAIM_HEADER, ".", and encBody and convert it to bytes using UTF-8 encoding. Store the result in the sig variable.
  8. Sign the sig bytes using the signingKey and encode the resulting signature using base64url encoding. Store the result in the encSig variable.
  9. Concatenate the ENCODED_CLAIM_HEADER, ".", encBody, ".", and encSig to form the final JWT.
  10. Return the final JWT.

Note: The values of ENCODED_CLAIM_HEADER and base32Encode methods are not provided in the given code snippet.

The issueJWT method in the JwtUtils class is responsible for generating a JSON Web Token (JWT) using the provided input parameters.

Here's a breakdown of what the method does:

  1. The method takes in a signingKey, publicUserKey, name, expiration, issuedAt, accSigningKeyPub, and nats parameter. These parameters are used to create the claims for the JWT.

  2. A new Claim object is created and the input parameters are assigned to the respective claim fields.

  3. The claimJson is generated by converting the Claim object to JSON.

  4. The jti claim field is computed by creating a SHA-256 hash of the claimJson and encoding it in base32.

  5. The claimJson is converted to base64url encoding.

  6. The signature (encSig) is computed by signing the concatenation of the encoded claim header, encoded claim body, and a dot delimiter using the signingKey.

  7. The JWT is constructed by concatenating the encoded claim header, encoded claim body, and encoded signature with dot delimiters.

  8. Finally, the generated JWT is returned.

This method is used to issue a JWT with the provided claims and is typically used for authentication and authorization purposes in a distributed system.

sequence diagram

NatsJetStreamClientError

NatsJetStreamClientError

The NatsJetStreamClientError class is a public class that represents an error that can occur when using the NATS JetStream client. This class is used to handle and manage error conditions specific to the JetStream functionality of the NATS messaging system.

private RuntimeException _instance(String msg)

private RuntimeException _instance(String msg) {
    if (kind == KIND_ILLEGAL_ARGUMENT) {
        return new IllegalArgumentException(msg);
    }
    return new IllegalStateException(msg);
}

The _instance method defined in the NatsJetStreamClientError class in the io.nats.client.support package is responsible for creating and returning a RuntimeException based on the provided message.

Here is a step-by-step description of what the _instance method does:

  1. The method takes a single parameter msg, which represents the error message that will be included in the created exception object.

  2. The method first checks the value of the kind variable.

  3. If the value of kind is KIND_ILLEGAL_ARGUMENT, the method creates a new IllegalArgumentException instance with the provided msg as the error message.

  4. If the value of kind is not KIND_ILLEGAL_ARGUMENT, the method creates a new IllegalStateException instance with the provided msg as the error message.

  5. The created exception object is then returned by the method.

Note: The exact implementation of KIND_ILLEGAL_ARGUMENT and the declaration of kind are not shown in the provided code snippet, so the behavior of the method may vary depending on the actual values and logic in the code.

The _instance method, defined in the NatsJetStreamClientError class of the io.nats.client.support package, is a private method that returns a RuntimeException based on the given message parameter.

If the kind variable is equal to KIND_ILLEGAL_ARGUMENT, it creates and returns an IllegalArgumentException with the given message. Otherwise, it creates and returns an IllegalStateException with the given message.

sequence diagram

JsonValue

JsonValue

The JsonValue class is a public class in Java that implements the JsonSerializable interface. It represents a value in JSON format and provides methods to serialize and deserialize JSON objects. This class is commonly used in software engineering for handling JSON data in applications.

@Override

public String toJson()

@Override
public String toJson() {
    switch(type) {
        case STRING:
            return valueString(string);
        case BOOL:
            return valueString(bool);
        case MAP:
            return valueString(map);
        case ARRAY:
            return valueString(array);
        case INTEGER:
            return i.toString();
        case LONG:
            return l.toString();
        case DOUBLE:
            return d.toString();
        case FLOAT:
            return f.toString();
        case BIG_DECIMAL:
            return bd.toString();
        case BIG_INTEGER:
            return bi.toString();
        default:
            return NULL_STR;
    }
}

The toJson() method in the JsonValue class, defined in the io.nats.client.support package, converts the value of an object to its respective JSON representation. It does this by switching on the type of the object, and returning the JSON representation based on the type.

Here is a step-by-step breakdown of what the toJson() method does:

  1. Start of the method toJson().
  2. Switch on the type of the object.
  3. If the type is STRING, return the JSON representation of the string value using the helper method valueString(string).
  4. If the type is BOOL, return the JSON representation of the bool value using the helper method valueString(bool).
  5. If the type is MAP, return the JSON representation of the map value using the helper method valueString(map).
  6. If the type is ARRAY, return the JSON representation of the array value using the helper method valueString(array).
  7. If the type is INTEGER, return the toString() representation of the i value.
  8. If the type is LONG, return the toString() representation of the l value.
  9. If the type is DOUBLE, return the toString() representation of the d value.
  10. If the type is FLOAT, return the toString() representation of the f value.
  11. If the type is BIG_DECIMAL, return the toString() representation of the bd value.
  12. If the type is BIG_INTEGER, return the toString() representation of the bi value.
  13. If none of the above cases match, return the string representation of NULL_STR.
  14. End of the toJson() method.

Note that the valueString() helper method is used for converting certain types such as string, bool, map, and array to their respective JSON representations.

This is a high-level overview of what the toJson() method in the JsonValue class does based on its body. The exact functionality and behavior may depend on the implementation and usage of the JsonValue class and its dependencies.

The toJson method in the JsonValue class is used to convert the current instance of JsonValue into a JSON string representation.

Based on the implementation, the method performs a switch statement on the type of the JsonValue. Depending on the type, it returns the JSON representation of the corresponding value.

If the type is STRING, it returns the JSON representation of the string value. If the type is BOOL, it returns the JSON representation of the bool value. If the type is MAP, it returns the JSON representation of the map value. If the type is ARRAY, it returns the JSON representation of the array value.

If the type is INTEGER, LONG, DOUBLE, FLOAT, BIG_DECIMAL, or BIG_INTEGER, it returns the string representation of the respective value.

If none of the above cases match, it returns the JSON representation of null.

sequence diagram

private String valueString(Map<String, JsonValue> map)

private String valueString(Map<String, JsonValue> map) {
    StringBuilder sbo = beginJson();
    for (String key : map.keySet()) {
        addField(sbo, key, map.get(key));
    }
    return endJson(sbo).toString();
}

The valueString method in the JsonValue class is used to convert a given map of key-value pairs into a JSON string. Here is a step-by-step description of what this method does:

  1. Declare a StringBuilder object named sbo and initialize it by calling the beginJson method. This method is not defined in the given code snippet, so its implementation details are not known.

  2. Iterate over the keys of the map using a for-each loop. For each key, do the following:

    a. Call the addField method, passing in the sbo string builder, the current key, and the corresponding value from the map. The addField method is not defined in the given code snippet, so its implementation details are not known.

  3. After the iteration is complete, call the endJson method, passing in the sbo string builder. This method is not defined in the given code snippet, so its implementation details are not known. The method should finalize the creation of the JSON string.

  4. Convert the sbo string builder to a string by calling the toString method.

  5. Return the JSON string.

Please note that without the implementation details of the beginJson, addField, and endJson methods, it is not possible to fully determine the behavior of the valueString method.

The valueString method is a private method defined in the JsonValue class within the io.nats.client.support package. It takes in a Map of type String and JsonValue as input.

The method loops through the keys of the map and for each key, it calls the addField method and passes the sbo (a StringBuilder) and the corresponding value associated with the key in the map. The addField method is responsible for appending the formatted JSON field to the sbo builder.

After iterating through all the keys in the map, the method calls the endJson method and passes the sbo builder to generate the closing part of the JSON string. The endJson method returns a StringBuilder with the complete JSON string.

Finally, the method converts the StringBuilder to a String by calling the toString method and returns the result.

sequence diagram

private String valueString(List list)

private String valueString(List<JsonValue> list) {
    StringBuilder sba = beginArray();
    for (JsonValue v : list) {
        sba.append(v.toJson());
        sba.append(COMMA);
    }
    return endArray(sba).toString();
}

The valueString method, defined in the JsonValue class in the io.nats.client.support package, takes a list of JsonValue objects as its parameter.

Here is a step-by-step description of what the valueString method does based on its body:

  1. The method starts by creating a StringBuilder object named sba by calling the beginArray method. The beginArray method is not shown in the provided code snippet, but it is assumed to initialize the StringBuilder with an opening array bracket "[".

  2. The method then enters a loop that iterates over each JsonValue object in the list parameter.

  3. Inside the loop, the toJson method is called on each JsonValue object v. The toJson method converts the JsonValue object into its string representation.

  4. The resulting string is appended to the sba StringBuilder object by calling the append method.

  5. After appending the string representation of the JsonValue object, a comma (,) is also appended to the sba StringBuilder object by calling the append method with the COMMA constant.

  6. Steps 4 and 5 are repeated for each JsonValue object in the list parameter.

  7. Once the loop iteration is complete, the sba StringBuilder object is passed to the endArray method. The endArray method is not shown in the provided code snippet, but it is assumed to append the closing array bracket "]" to the StringBuilder and perform any necessary post-processing.

  8. The endArray method returns the sba StringBuilder object as a String by calling the toString method.

  9. Finally, the valueString method returns the String representation of the StringBuilder object.

In summary, the valueString method takes a list of JsonValue objects, converts each object into its string representation, and combines them with commas to form a JSON array. The resulting JSON array string is returned as the output of the method.

The valueString method in the io.nats.client.support.JsonValue class is used to convert a list of JsonValue objects into a string representation.

It takes a List<JsonValue> as input and iterates through the elements of the list. For each JsonValue element, it appends the result of calling its toJson() method to a StringBuilder, followed by a comma.

Finally, it calls the endArray method, passing the StringBuilder as a parameter, and converts the result to a string by calling toString().

The purpose of this method is to generate a string representation of the given list of JsonValue objects, suitable for JSON serialization or other similar purposes.

sequence diagram

Validator

Validator

The Validator class is an abstract class that provides a framework for implementing various validation logic in a software application. It serves as a base class for creating specific validator classes that can be used to validate different types of data or entities.

public static String validateSubject(String subject, String label, boolean required, boolean cantEndWithGt)

public static String validateSubject(String subject, String label, boolean required, boolean cantEndWithGt) {
    if (emptyAsNull(subject) == null) {
        if (required) {
            throw new IllegalArgumentException(label + " cannot be null or empty.");
        }
        return null;
    }
    String[] segments = subject.split("\\.");
    for (int x = 0; x < segments.length; x++) {
        String segment = segments[x];
        if (segment.equals(">")) {
            if (cantEndWithGt || x != segments.length - 1) {
                // if it can end with gt, gt must be last segment
                throw new IllegalArgumentException(label + " cannot contain '>'");
            }
        } else if (!segment.equals("*") && notPrintable(segment)) {
            throw new IllegalArgumentException(label + " must be printable characters only.");
        }
    }
    return subject;
}

The validateSubject method in class io.nats.client.support.Validator is used to validate a subject string based on certain criteria. Here is a step-by-step description of what the method does:

  1. The method takes four parameters: subject (the subject string to validate), label (a label used in error messages), required (a boolean flag indicating if the subject is required), and cantEndWithGt (a boolean flag indicating if the subject cannot end with '>').

  2. The method first checks if the subject is null or empty by calling the emptyAsNull helper method. If the subject is null or empty and is marked as required, an IllegalArgumentException is thrown with an error message stating that the label cannot be null or empty. If the subject is not required and is null or empty, the method returns null.

  3. If the subject is not null or empty, the method splits the subject into segments using the dot ('.') as the delimiter. Each segment represents a part of the subject string.

  4. The method then iterates over each segment in the segments array.

  5. For each segment, the method checks if it is equal to '>'. If it is, two conditions are checked: (a) if cantEndWithGt is true or if the segment is not the last segment in the subject. If either of these conditions is true, an IllegalArgumentException is thrown with an error message stating that the label cannot contain '>'. This check is to ensure that if the subject is not allowed to end with '>', it must be the last segment.

  6. If the segment is not equal to '>', the method checks if it is equal to '' or if it contains any non-printable characters. The notPrintable helper method is used to determine if a segment contains any non-printable characters. If the segment is neither '' nor consists of only printable characters, an IllegalArgumentException is thrown with an error message stating that the label must be printable characters only.

  7. If all segments pass the validation checks, the method returns the original subject string.

Overall, the validateSubject method ensures that the provided subject string meets the specified criteria, such as not being null or empty, not containing '>', and consisting of only printable characters. If any of the validation conditions fail, an IllegalArgumentException is thrown.

The validateSubject method in the Validator class is used to validate a subject string. It takes four parameters: subject, label, required, and cantEndWithGt.

The method first checks if the subject string is null or empty. If it is and the required parameter is true, it throws an IllegalArgumentException with a message indicating that the subject cannot be null or empty. If the subject is null or empty and the required parameter is false, it returns null.

Next, the method splits the subject string into segments using the dot (".") as the separator. It then iterates over each segment and performs validation checks.

If a segment equals ">", the method checks if cantEndWithGt is true or if it is the last segment in the subject. If either condition is true, it throws an IllegalArgumentException with a message indicating that the subject cannot contain ">", as it violates the validation rule.

If a segment is neither "*" nor printable, the method throws an IllegalArgumentException with a message indicating that the subject must consist of printable characters only.

Finally, if all validation checks pass, the method returns the subject string.

sequence diagram

public static String validatePrefixOrDomain(String s, String label, boolean required)

public static String validatePrefixOrDomain(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (s.startsWith(DOT)) {
            throw new IllegalArgumentException(label + " cannot start with `.` [" + s + "]");
        }
        if (notPrintableOrHasWildGt(s)) {
            throw new IllegalArgumentException(label + " must be in the printable ASCII range and cannot include `*`, `>` [" + s + "]");
        }
        return s;
    });
}

The validatePrefixOrDomain method, defined in the io.nats.client.support.Validator class, is used to validate a given string s as either a prefix or domain. It takes three parameters: s (the string to be validated), label (the label used in error messages), and required (a boolean indicating whether the string is required or not).

Here is the step-by-step description of what the validatePrefixOrDomain method does based on its body:

  1. Call the private method _validate with the parameters s, required, label, and a lambda expression. This lambda expression contains the validation logic for the string.

  2. In the lambda expression:

    • Check if the string s starts with a dot (.). If it does, throw an IllegalArgumentException with an error message indicating that the label cannot start with a dot.
    • Check if the string s is not printable ASCII or if it contains the characters * or >. If it does, throw an IllegalArgumentException with an error message indicating that the label must be in the printable ASCII range and cannot include * or >.
    • If the string passes the above checks, return the string s.
  3. Return the string s from the validatePrefixOrDomain method.

Note: The _validate method is not described in the provided code snippet, but it can be inferred that it performs common validation logic and error handling.

The validatePrefixOrDomain method is used to validate a prefix or domain string.

The method takes three parameters: s which is the string to be validated, label which is a label to describe the string being validated, and required which is a boolean value indicating if the string is required or not.

Inside the method, the _validate function is called with the string, required flag, and label as arguments. This function performs the actual validation.

The validation checks for two conditions. First, it checks if the string starts with a dot (.). If it does, it throws an IllegalArgumentException with a message indicating that the string cannot start with a dot.

Second, it checks if the string is not printable ASCII or contains wildcard characters (* or >). If either of these conditions is true, it throws an IllegalArgumentException with a message indicating that the string must be in the printable ASCII range and cannot contain wildcard characters.

If both checks pass, the method returns the validated string.

In summary, the validatePrefixOrDomain method ensures that a given prefix or domain string meets certain criteria: it does not start with a dot and it is printable ASCII without wildcard characters.

sequence diagram

public static String validateMustMatchIfBothSupplied(String s1, String s2, NatsJetStreamClientError err)

public static String validateMustMatchIfBothSupplied(String s1, String s2, NatsJetStreamClientError err) {
    // s1   | s2   || result
    // ---- | ---- || --------------
    // null | null || valid, null s2
    // null | y    || valid, y s2
    // x    | null || valid, x s1
    // x    | x    || valid, x s1
    // x    | y    || invalid
    s1 = emptyAsNull(s1);
    s2 = emptyAsNull(s2);
    if (s1 == null) {
        // s2 can be either null or y
        return s2;
    }
    // x / null or x / x
    if (s2 == null || s1.equals(s2)) {
        return s1;
    }
    throw err.instance();
}

Method: validateMustMatchIfBothSupplied

This method is defined in the io.nats.client.support.Validator class. It takes three parameters: s1 and s2 of type String, and err of type NatsJetStreamClientError. The purpose of this method is to validate whether s1 and s2 must match based on certain conditions.

Here is a step-by-step description of what the method does:

  1. Assigns the value of s1 after converting empty string to null using the emptyAsNull helper method.
  2. Assigns the value of s2 after converting empty string to null using the emptyAsNull helper method.
  3. Checks if s1 is null:
    • If s1 is null, it means that it is either null or an empty string.
    • Then, it checks if s2 is null or equal to "y".
      • If s2 is either null or "y", it returns the value of s2.
      • This is considered a valid scenario.
  4. If s1 is not null, it means that it has a non-empty value.
  5. Checks if s2 is null or equal to s1:
    • If s2 is null or equal to s1, it returns the value of s1.
    • This is considered a valid scenario.
  6. If none of the above conditions are met, it means that s1 and s2 have different non-null, non-empty values, which is considered an invalid scenario.
  7. Throws an instance of NatsJetStreamClientError using the err.instance() method to indicate an invalid scenario.

The method essentially follows a set of conditions to determine whether s1 and s2 must match or not. It returns the appropriate value or throws an error based on these conditions.

The validateMustMatchIfBothSupplied method in the io.nats.client.support.Validator class is used to validate two string inputs, s1 and s2, and ensure that they match certain conditions.

The method starts by converting any empty strings to null using the emptyAsNull helper method.

The method then proceeds to check various combinations of s1 and s2 using a table:

  • If both s1 and s2 are null, the method returns null, indicating a valid condition.
  • If s1 is null and s2 is not null, the method returns s2, indicating a valid condition.
  • If s1 is not null and s2 is null or s1 is equal to s2, the method returns s1, indicating a valid condition.
  • If none of the above conditions are met, the method throws an exception using the provided NatsJetStreamClientError instance.

In summary, this method validates s1 and s2 based on the conditions described in the table and returns the appropriate value or throws an exception.

sequence diagram

public static String required(String s, String label)

public static String required(String s, String label) {
    if (emptyAsNull(s) == null) {
        throw new IllegalArgumentException(label + " cannot be null or empty.");
    }
    return s;
}

The required method in the io.nats.client.support.Validator class is used to validate a string value and ensure that it is not null or empty. It takes two parameters:

  1. s - the string value that needs to be validated.
  2. label - the label or name of the string value, which is used in the error message if the validation fails.

Here is a step-by-step description of what the required method is doing:

  1. Check if the s string value is empty or null by calling the emptyAsNull method, which is not provided in the given code snippet. Assuming that this method returns null if the string value is empty or null and returns the original string value otherwise.

  2. If the result of emptyAsNull(s) is null, it means that the string value is either empty or null, which is considered invalid.

  3. Throw an IllegalArgumentException with an error message indicating that the string value specified by the label parameter cannot be null or empty.

  4. If the string value passes the validation, i.e., it is not empty or null, return the original string value.

In summary, the required method ensures that a string value is not null or empty and throws an IllegalArgumentException if it is.

The required method, defined in the io.nats.client.support.Validator class, is used to validate that a given string parameter is not null or empty.

The method takes two parameters: s, which is the string to be validated, and label, which is a label or description of the string parameter.

Inside the method, it first checks if the given string parameter is null or empty using the emptyAsNull helper method. If the string is null or empty, it throws an IllegalArgumentException with a message indicating that the string parameter cannot be null or empty, using the provided label.

If the string is not null or empty, the method simply returns the original string.

This method is useful for enforcing that a required string parameter is provided, and can be used to validate user input or ensure that necessary data is provided before continuing with further processing.

sequence diagram

public static T required(T o, String label)

public static <T> T required(T o, String label) {
    if (o == null) {
        throw new IllegalArgumentException(label + " cannot be null or empty.");
    }
    return o;
}

Method Description - required()

This method is defined in the io.nats.client.support.Validator class and is used to validate if a given object o is null or not.

The method has the following signature:

public static <T> T required(T o, String label) {
    // Method body
}

Parameters:

  • o: The object that needs to be validated.
  • label: A string value representing a label or description for the object o.

Return Value:

This method returns the validated object o if it is not null.

Method Body:

The method body checks if the object o is null using the condition o == null. If the condition evaluates to true, it throws an IllegalArgumentException with an error message formatted as "{label} cannot be null or empty.", where {label} is the value passed as the label parameter.

If the object o is not null, it directly returns the object o.

Example Usage:

String text = "Sample Text";
String validatedText = Validator.required(text, "Text");

// The value of 'validatedText' will be "Sample Text"

In the above example, the required() method is used to validate if the text object is null or not. Since the text object is not null, it is returned as the validated object.

The required method in the io.nats.client.support.Validator class is a static method that takes two parameters: an object of type T (o) and a String (label).

This method is used to check if the object o is null. If o is null, the method throws an IllegalArgumentException with a descriptive message indicating that the label (provided as a parameter) cannot be null or empty.

Otherwise, if o is not null, the method simply returns the object o.

This method is typically used to validate that a required parameter or argument in a method call is provided, and it serves as a convenient way to enforce a non-null value.

sequence diagram

public static String _validate(String s, boolean required, String label, Check check)

public static String _validate(String s, boolean required, String label, Check check) {
    if (emptyAsNull(s) == null) {
        if (required) {
            throw new IllegalArgumentException(label + " cannot be null or empty.");
        }
        return null;
    }
    return check.check();
}

The method _validate in the class io.nats.client.support.Validator performs the following steps:

  1. The method takes four parameters:

    • s: A string to be validated.
    • required: A boolean value indicating whether the string is required.
    • label: A string label for the parameter being validated.
    • check: An instance of the Check functional interface which provides a check method to be executed.
  2. If the string s is empty or null (determined by the emptyAsNull method), the following actions are taken:

    • If required is true, an IllegalArgumentException is thrown with a message indicating that the label cannot be null or empty.
    • If required is false, null is returned.
  3. If the string s is not empty or null, the check.check() method is called. The purpose of this method is not specified in the given code snippet, but it is expected to perform some kind of validation or processing on the provided string. The return value of the check method is then returned from the _validate method.

Note: The implementation of the emptyAsNull method and the exact behavior of the check method are not available in the provided code snippet, so further analysis would be required to understand their functionality.

The _validate method is a static method defined in the Validator class in the io.nats.client.support package.

This method takes four parameters:

  1. String s - the value to be validated
  2. boolean required - specifies whether the value is required or not
  3. String label - a label for the value being validated (used for error messages)
  4. Check check - an instance of the Check interface, which is responsible for performing the actual validation logic

The purpose of this method is to validate a given value based on the specified requirements.

First, it checks if the value is empty or null by invoking the emptyAsNull method (which is not shown in the provided code). If the value is empty or null and it is marked as required, it throws an IllegalArgumentException with an appropriate error message.

If the value is not empty or null, it then calls the check.check() method, which is responsible for performing the actual validation logic. The return value of this method is then returned by the _validate method.

Overall, this method provides a reusable way to validate a value based on the specified requirements and perform custom validation logic using the Check interface.

sequence diagram

public static String validateMaxLength(String s, int maxLength, boolean required, String label)

public static String validateMaxLength(String s, int maxLength, boolean required, String label) {
    return _validate(s, required, label, () -> {
        int len = s.getBytes(StandardCharsets.UTF_8).length;
        if (len > maxLength) {
            throw new IllegalArgumentException(label + " cannot be longer than " + maxLength + " bytes but was " + len + " bytes");
        }
        return s;
    });
}

The validateMaxLength method in the io.nats.client.support.Validator class is used to validate a string against a maximum length. Here is a step-by-step description of what the method does:

  1. The method takes four parameters:

    • s - the string to be validated
    • maxLength - the maximum length allowed for the string
    • required - a boolean value indicating if the string is required or not
    • label - a label to identify the string in case of an error message
  2. The method calls the _validate method, passing the s, required, label, and a lambda expression as parameters. The lambda expression is used to define the validation logic.

  3. Inside the lambda expression, the method calculates the length of the string in bytes using the UTF-8 character encoding. The getBytes method is used to convert the string to a byte array, and the length property of the byte array is then used to get the length in bytes.

  4. If the length of the string is greater than the maxLength parameter, an IllegalArgumentException is thrown. The exception message includes the label, maxLength, and the actual length of the string in bytes.

  5. If the string passes the length validation, it is returned as the result of the method.

In summary, the validateMaxLength method checks if a given string exceeds a maximum length in bytes. It throws an exception if the length is exceeded and returns the string if it is within the allowed length.

The validateMaxLength method, defined in the Validator class in the io.nats.client.support package, is used to validate if a given string s is not longer than a specified maxLength in bytes.

The method takes four parameters:

  • s: The string to be validated.
  • maxLength: The maximum allowed length of the string in bytes.
  • required: A boolean value indicating whether the string is required or not.
  • label: A label to identify the string being validated.

Internally, the method calculates the length of the string s in bytes using the UTF-8 character encoding. If the length exceeds the maxLength, the method throws an IllegalArgumentException with an error message indicating the violation.

If the string passes the validation, it is returned unchanged.

Overall, validateMaxLength provides a convenient way to validate the maximum length of a string in bytes while considering the UTF-8 encoding.

sequence diagram

public static String validatePrintable(String s, String label, boolean required)

public static String validatePrintable(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notPrintable(s)) {
            throw new IllegalArgumentException(label + " must be in the printable ASCII range [" + s + "]");
        }
        return s;
    });
}

The validatePrintable method, defined in the io.nats.client.support.Validator class, is responsible for validating a given string s based on its printability in the ASCII range. It takes three parameters: the string to validate s, a label for the string label, and a boolean flag indicating whether the string is required or not required.

Here's a step-by-step breakdown of what the method is doing:

  1. The method delegates the actual validation to the _validate method, passing in the string s, the boolean flag required, the string label label, and a lambda expression.

  2. The lambda expression () -> { ... } defines an inline function that is executed within the _validate method.

  3. Within the lambda expression, the method first checks if the string s is not printable by calling the notPrintable function. If the string is not printable, an IllegalArgumentException is thrown. The exception message includes the label and the actual string value.

  4. If the string is printable, the method returns the original string s.

Overall, the validatePrintable method ensures that a given string is within the printable ASCII range and throws an exception if it is not.

The validatePrintable method in the Validator class is a public static method that takes three parameters:

  1. s - a String that needs to be validated
  2. label - a String representing the label of the value being validated
  3. required - a boolean indicating if the value is required to be non-null and non-empty

The purpose of this method is to validate that the provided s parameter contains only printable ASCII characters. If the s parameter contains any characters that are not within the printable ASCII range, an IllegalArgumentException is thrown with an error message indicating the violation.

The underlying implementation of this method involves calling a private method _validate from within the validatePrintable method, passing in the necessary parameters. This private method handles the common validation logic for various types of validations and returns the validated s parameter if it passes all the validation checks.

sequence diagram

public static String validatePrintableExceptWildDotGt(String s, String label, boolean required)

public static String validatePrintableExceptWildDotGt(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notPrintableOrHasWildGtDot(s)) {
            throw new IllegalArgumentException(label + " must be in the printable ASCII range and cannot include `*`, `.` or `>` [" + s + "]");
        }
        return s;
    });
}

The validatePrintableExceptWildDotGt method is a static method defined in the Validator class located in the io.nats.client.support package. It takes three parameters: String s, String label, and boolean required. It returns a String.

Here is a step-by-step description of what this method does:

  1. It calls the _validate method passing in the s parameter, required parameter, label parameter, and a lambda expression as arguments. This method is responsible for performing the actual validation and throwing an exception if the validation fails.

  2. Inside the lambda expression, it checks whether the s string is not in the printable ASCII range or contains the characters *, ., or >. This check is done using the notPrintableOrHasWildGtDot method.

  3. If the check in step 2 fails, it throws an IllegalArgumentException with a message that includes the label, the invalid string s, and a description of the invalid characters.

  4. If the check in step 2 passes, it returns the original string s.

Overall, this method is used to validate a string s to ensure that it is in the printable ASCII range and does not contain the characters *, ., or >. If the validation fails, an exception is thrown.

The method validatePrintableExceptWildDotGt in the class Validator is used to validate a string s to ensure that it is in the printable ASCII range and does not include the characters *, ., or >.

If the string s is not printable or contains any of the prohibited characters, an IllegalArgumentException is thrown with a message indicating the invalid characters found in the string.

Otherwise, the method returns the validated string s.

sequence diagram

public static String validatePrintableExceptWildDotGtSlashes(String s, String label, boolean required)

public static String validatePrintableExceptWildDotGtSlashes(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notPrintableOrHasWildGtDotSlashes(s)) {
            throw new IllegalArgumentException(label + " must be in the printable ASCII range and cannot include `*`, `.`, `>`, `\\` or  `/` [" + s + "]");
        }
        return s;
    });
}

Method Description: validatePrintableExceptWildDotGtSlashes

The validatePrintableExceptWildDotGtSlashes method is defined in the io.nats.client.support.Validator class. This method is used to validate a string and ensure that it only contains printable ASCII characters, except for the characters *, ., >, \, or /.

Method Signature

public static String validatePrintableExceptWildDotGtSlashes(String s, String label, boolean required)

Parameters

  • s : The string to be validated
  • label : The label or name of the string being validated
  • required : A boolean flag indicating whether the string is required or not

Return Value

  • The validated string s

Method Body

The method call _validate(s, required, label, () -> {...}) is used to perform the validation. It uses a lambda expression to define the validation logic.

The validation logic checks if the string s is not printable or contains any of the following characters: *, ., >, \, or /. If the validation fails, an IllegalArgumentException is thrown with an error message that includes the label and the invalid string. Otherwise, the method returns the validated string s.

Example error message:

[label] must be in the printable ASCII range and cannot include `*`, `.`, `>`, `\` or  `/` [invalidString]

Exceptions

  • IllegalArgumentException: Thrown if the validation fails

The validatePrintableExceptWildDotGtSlashes method is a static method defined in the Validator class within the io.nats.client.support package. This method takes three parameters: s, label, and required.

The purpose of this method is to validate the input string s and ensure that it contains only printable ASCII characters, excluding specific characters such as *, ., >, \, and /. If the input string s contains any of these forbidden characters or is not within the printable ASCII range, an IllegalArgumentException is thrown with a descriptive message including the label and the invalid input.

The method follows a functional programming style, making use of a lambda expression to perform the actual validation. The lambda expression checks if the input string s is not printable or contains any of the forbidden characters using the notPrintableOrHasWildGtDotSlashes method. If any of these conditions are true, the validation fails and an IllegalArgumentException is thrown. Otherwise, the validated string s is returned.

Overall, the validatePrintableExceptWildDotGtSlashes method ensures that the input string s meets the required criteria of being printable while excluding specific forbidden characters.

sequence diagram

public static String validatePrintableExceptWildGt(String s, String label, boolean required)

public static String validatePrintableExceptWildGt(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notPrintableOrHasWildGt(s)) {
            throw new IllegalArgumentException(label + " must be in the printable ASCII range and cannot include `*` or `>` [" + s + "]");
        }
        return s;
    });
}

Description of the validatePrintableExceptWildGt Method

The validatePrintableExceptWildGt method is defined in the io.nats.client.support.Validator class. It takes three parameters:

  1. s - A string that needs to be validated.
  2. label - A string label that provides context to the validation process.
  3. required - A boolean flag that indicates whether the string is required or not.

The purpose of this method is to validate the input string s and ensure that it only contains printable characters from the ASCII range, except for the characters * and >. The validation process includes checking if the string is required and whether it meets the specified criteria.

The method calls a private method _validate to handle the validation process. Here is a step-by-step description of what happens in the method body:

  1. The method delegates the validation process to the _validate method, passing the input string s, the required flag, the provided label, and a lambda expression.

  2. The lambda expression represents the validation logic. It checks if the input string s is not printable or contains the characters * or >. If any of these conditions are true, it throws an IllegalArgumentException with a descriptive error message that includes the label and the input string s.

  3. If the lambda expression's validation logic passes without any exceptions being thrown, the method returns the input string s.

Overall, the validatePrintableExceptWildGt method ensures that the input string s is valid, printable, and does not contain the characters * or >. If the validation fails, it throws an exception with a detailed error message.

The method validatePrintableExceptWildGt in the Validator class is used to validate a string by checking if it contains any characters that are not within the printable ASCII range, and also if it includes the characters * or >.

The method takes three parameters: s (the string to be validated), label (a label that describes the string), and required (a boolean value indicating if the string is required).

If the string s is not printable or contains * or >, an IllegalArgumentException is thrown with a message indicating that the string must be in the printable ASCII range and cannot include * or >, along with the invalid string.

If the validation passes, the method returns the validated string s.

The method uses an underlying private method _validate to handle the common logic of validating the string and throwing an exception if necessary.

sequence diagram

public static String validateIsRestrictedTerm(String s, String label, boolean required)

public static String validateIsRestrictedTerm(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notRestrictedTerm(s)) {
            throw new IllegalArgumentException(label + " must only contain A-Z, a-z, 0-9, `-` or `_` [" + s + "]");
        }
        return s;
    });
}

Method validateIsRestrictedTerm in class io.nats.client.support.Validator

This method is a static method defined in class io.nats.client.support.Validator. It takes three parameters:

  1. String s: The input string that needs to be validated.
  2. String label: A label or name for the input string. This is used in exception messages for readability.
  3. boolean required: A flag indicating whether the input string is required (true) or optional (false).

The method returns a String value, which is the validated input string if it passes all the checks.

Method Signature

public static String validateIsRestrictedTerm(String s, String label, boolean required)

Steps

  1. The method calls a private method _validate with the input string s, the required flag, the label, and a lambda expression as parameters. The lambda expression contains the actual validation logic.
  2. Inside the lambda expression, the method checks if the input string s is not a restricted term. If it is not a restricted term, an IllegalArgumentException is thrown with a specific message indicating that the input string must only contain A-Z, a-z, 0-9, -, or _.
  3. If the input string passes the check, it is returned as the result of the method.

Please note that the actual implementation of the _validate and notRestrictedTerm methods is not provided in the given code snippet.

The method validateIsRestrictedTerm in the class Validator is used to check if a given string contains restricted terms. It takes three parameters: s (the string to be validated), label (a descriptive label for the string), and required (a boolean indicating if the string is required or not).

The method calls a private helper method _validate passing the string, label, and required as arguments, along with a lambda expression that performs the actual validation.

Inside the lambda expression, the method checks if s is not a restricted term by calling the notRestrictedTerm function. If s is not a restricted term, an IllegalArgumentException is thrown with a message indicating that the string should only contain letters, numbers, hyphens, or underscores.

If the string passes the validation, it is returned as the result of the method.

sequence diagram

public static String validateWildcardKvKey(String s, String label, boolean required)

public static String validateWildcardKvKey(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notWildcardKvKey(s)) {
            throw new IllegalArgumentException(label + " must only contain A-Z, a-z, 0-9, `*`, `-`, `_`, `/`, `=`, `>` or `.` and cannot start with `.` [" + s + "]");
        }
        return s;
    });
}

Method: validateWildcardKvKey

This method is defined in the io.nats.client.support.Validator class and is used to validate wildcard key-value pairs.

Parameters

The method takes the following parameters:

  • s (String): The key-value pair to be validated.
  • label (String): The label or name of the key-value pair.
  • required (boolean): Indicates whether the key-value pair is required or optional.

Return value

The method returns a String value.

Steps

The method performs the following steps:

  1. It calls the _validate method passing the s, required, label, and a lambda expression as arguments.
  2. Inside the lambda expression, it checks if the key-value pair does not match the required pattern by calling the notWildcardKvKey method.
  3. If the key-value pair is invalid, it throws an IllegalArgumentException with an error message indicating the invalid characters in the key-value pair.
  4. If the key-value pair is valid, it returns the key-value pair.

Note: The notWildcardKvKey method is not provided in the given code snippet, so the details of its implementation are unknown. This method is likely used to check if the given key-value pair matches a specific pattern.

The validateWildcardKvKey method in the Validator class is used to validate a given string s as a wildcard key-value key.

The method takes three parameters:

  • s: The string to be validated
  • label: A label used for error messages
  • required: A flag indicating whether the string is required or not

The method calls a private method _validate passing in the string s, the required flag, the label, and a lambda expression. If the string s does not meet the validation criteria, an IllegalArgumentException is thrown with an appropriate error message indicating that the string must only contain certain characters and cannot start with a dot.

If the string s passes the validation, it is returned unchanged.

sequence diagram

public static String validateNonWildcardKvKey(String s, String label, boolean required)

public static String validateNonWildcardKvKey(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (notNonWildcardKvKey(s)) {
            throw new IllegalArgumentException(label + " must only contain A-Z, a-z, 0-9, `-`, `_`, `/`, `=` or `.` and cannot start with `.` [" + s + "]");
        }
        return s;
    });
}

The validateNonWildcardKvKey method within the io.nats.client.support.Validator class is responsible for validating a given key string based on specific criteria.

Here is a step-by-step description of what the method is doing:

  1. The method accepts three parameters:

    • s - the key string to be validated
    • label - a label to describe the key (used in exception messages)
    • required - a flag indicating if the key is required or not
  2. The method calls a private method _validate with the parameters s, required, label, and a lambda expression.

  3. Within the lambda expression, the method checks if the key string s does not meet the criteria of a non-wildcard key by calling the notNonWildcardKvKey helper method. If the key string does not meet the criteria, an IllegalArgumentException is thrown with an informative error message.

  4. The error message indicates that the key must only contain letters A-Z (uppercase and lowercase), digits 0-9, hyphen (-), underscore (_), forward slash (/), equal sign (=), or period (.). Additionally, the key cannot start with a period. The original key string that failed the validation is included in the error message.

  5. If the key string passes all the validation checks, it is returned as the result of the method.

Note: The implementation of the notNonWildcardKvKey method is not provided in the given code snippet. Its purpose is to determine if the key string violates the criteria for a non-wildcard key.

The validateNonWildcardKvKey method is a static method in the Validator class that takes in three parameters: a String s, a String label, and a boolean required.

This method is used to validate a non-wildcard key (s) for a key-value pair. It ensures that the key only contains valid characters and does not violate any restrictions.

If the key is found to be invalid, an IllegalArgumentException is thrown, with a detailed error message indicating the specific validation failure. If the key is deemed valid, it is returned as the output of the method.

sequence diagram

public static int validateMaxHistory(int max)

public static int validateMaxHistory(int max) {
    if (max < 1 || max > MAX_HISTORY_PER_KEY) {
        throw new IllegalArgumentException("Max History must be from 1 to " + MAX_HISTORY_PER_KEY + " inclusive.");
    }
    return max;
}

Method Description: validateMaxHistory()

This method is defined in the class io.nats.client.support.Validator. It takes an integer parameter max and returns an integer value.

Parameters:

  • max (type: int): The value to be validated.

Steps:

  1. Check if the value of max is less than 1 or greater than a constant value MAX_HISTORY_PER_KEY.
  2. If the condition in step 1 is true, throw an IllegalArgumentException with a message stating that the max value must be between 1 and MAX_HISTORY_PER_KEY, inclusive.
  3. If the condition in step 1 is false, return the max value.

Return Value:

  • The validated max value.

The validateMaxHistory method in the Validator class of the io.nats.client.support package is used to validate a given maximum history value.

The method takes an integer parameter max, representing the maximum history value to be validated. It checks if the value is less than 1 or greater than a constant variable MAX_HISTORY_PER_KEY. If either of these conditions is true, it throws an IllegalArgumentException with an error message stating that the maximum history must be between 1 and MAX_HISTORY_PER_KEY, inclusive.

If the input value passes the validation, it simply returns the value itself.

This method is useful in ensuring that the maximum history value provided by the caller falls within the permissible range.

sequence diagram

public static int validateNumberOfReplicas(int replicas)

public static int validateNumberOfReplicas(int replicas) {
    if (replicas < 1 || replicas > 5) {
        throw new IllegalArgumentException("Replicas must be from 1 to 5 inclusive.");
    }
    return replicas;
}

The method validateNumberOfReplicas is defined in the class io.nats.client.support.Validator and is responsible for validating the number of replicas passed as an argument.

Here is a step-by-step description of what this method does based on its body:

  1. The method takes an integer argument replicas.

  2. It checks if the value of replicas is less than 1 or greater than 5 using the logical OR operator (||).

  3. If the condition evaluates to true, it means that the value of replicas is either less than 1 or greater than 5, which is invalid. In this case, an IllegalArgumentException is thrown with the message "Replicas must be from 1 to 5 inclusive." This exception is used to indicate that an illegal argument has been passed to the method.

  4. If the condition in step 2 evaluates to false, it means that the value of replicas is within the valid range of 1 to 5 inclusive.

  5. In this case, the method simply returns the value of replicas.

Overall, the purpose of this method is to ensure that the number of replicas provided is within the valid range of 1 to 5. If an invalid value is detected, it throws an exception, otherwise, it returns the given replica count as is.

The method validateNumberOfReplicas, defined in the class io.nats.client.support.Validator, is used to validate the number of replicas in a system. It takes an integer argument replicas and checks if it is within the valid range of 1 to 5 (inclusive). If the replicas value is outside this range, an IllegalArgumentException is thrown with an appropriate error message. If the replicas value is valid, it is returned as the output of the method.

This method is useful to ensure that the number of replicas specified for a system is within a valid and supported range. If the replicas value is invalid, it can lead to unexpected behavior or errors in the system.

sequence diagram

public static Duration validateDurationRequired(Duration d)

public static Duration validateDurationRequired(Duration d) {
    if (d == null || d.isZero() || d.isNegative()) {
        throw new IllegalArgumentException("Duration required and must be greater than 0.");
    }
    return d;
}

Method Definition: The validateDurationRequired method is defined in the io.nats.client.support.Validator class as a public static method.

Method Signature: public static Duration validateDurationRequired(Duration d)

Method Description: This method takes a Duration object as input and validates it to ensure that it is not null, not zero, and not negative.

Step-by-Step Description:

  1. Check if the input Duration object, d, is null or if it is equal to zero or if it is negative.
  2. If any of the above conditions are true, throw an IllegalArgumentException with the message "Duration required and must be greater than 0."
  3. If none of the above conditions are true, return the input Duration object, d.

The validateDurationRequired method in the io.nats.client.support.Validator class checks if a provided Duration meets specific requirements. The method takes in a Duration object as a parameter.

If the provided Duration is null, zero, or negative, the method throws an IllegalArgumentException with the message "Duration required and must be greater than 0.". Otherwise, it returns the provided Duration.

This method is used to ensure that a valid and non-zero Duration value is provided, rejecting any invalid inputs.

sequence diagram

public static Duration validateDurationNotRequiredGtOrEqZero(Duration d, Duration ifNull)

public static Duration validateDurationNotRequiredGtOrEqZero(Duration d, Duration ifNull) {
    if (d == null) {
        return ifNull;
    }
    if (d.isNegative()) {
        throw new IllegalArgumentException("Duration must be greater than or equal to 0.");
    }
    return d;
}

The method validateDurationNotRequiredGtOrEqZero in the class io.nats.client.support.Validator performs the following steps:

  1. Check if the input d is null.

    • If d is null, return the input ifNull duration.
  2. Check if the input d is negative.

    • If d is negative, throw an IllegalArgumentException with the message "Duration must be greater than or equal to 0."
  3. If both conditions are false, return the input d duration.

This method is used to validate a Duration object, ensuring that it is not null and greater than or equal to 0.

The method validateDurationNotRequiredGtOrEqZero checks if a given Duration is greater than or equal to zero. If the duration is null, it returns a specified default value (ifNull). If the duration is negative, it throws an IllegalArgumentException with a descriptive error message. If the duration is valid (greater than or equal to zero), it returns the duration itself.

sequence diagram

public static Duration validateDurationNotRequiredGtOrEqZero(long millis)

public static Duration validateDurationNotRequiredGtOrEqZero(long millis) {
    if (millis < 0) {
        throw new IllegalArgumentException("Duration must be greater than or equal to 0.");
    }
    return Duration.ofMillis(millis);
}

Method Description: validateDurationNotRequiredGtOrEqZero

This method is defined in the class io.nats.client.support.Validator and is used to validate a duration value to ensure that it is greater than or equal to zero.

Method Signature:

public static Duration validateDurationNotRequiredGtOrEqZero(long millis)

Method Body:

if (millis < 0) {
    throw new IllegalArgumentException("Duration must be greater than or equal to 0.");
}
return Duration.ofMillis(millis);

Steps:

The method validateDurationNotRequiredGtOrEqZero takes a long value representing duration in milliseconds as input.

  1. Check if the input millis is less than zero.
  2. If step 1 is true, throw an IllegalArgumentException with the message "Duration must be greater than or equal to 0."
  3. If step 1 is false, create a Duration object using the value of millis as the duration in milliseconds.
  4. Return the created Duration object.

Note: The purpose of this method is to ensure that the duration value provided is valid and meets the requirement of being greater than or equal to zero.

The validateDurationNotRequiredGtOrEqZero method is a static method defined in the Validator class in the io.nats.client.support package.

This method takes a long parameter millis representing a duration in milliseconds. It validates that the duration is not negative (i.e., greater than or equal to zero). If the duration is negative, it throws an IllegalArgumentException with the message "Duration must be greater than or equal to 0."

If the duration is valid (greater than or equal to zero), it returns a Duration object representing the specified number of milliseconds.

sequence diagram

public static String validateNotNull(String s, String fieldName)

public static String validateNotNull(String s, String fieldName) {
    if (s == null) {
        throw new IllegalArgumentException(fieldName + " cannot be null");
    }
    return s;
}

The validateNotNull method is a static method defined in the io.nats.client.support.Validator class. This method takes two parameters: a string s and a string fieldName. The purpose of this method is to validate that the provided string (s) is not null.

The method implementation starts with an if statement that checks if the s parameter is null. If it is null, an IllegalArgumentException is thrown with a message that includes the fieldName parameter. This exception indicates that the provided field name cannot be null.

If the s parameter is not null, the method simply returns the s string.

In summary, the validateNotNull method ensures that the provided string is not null, and if it is null, it throws an exception. Otherwise, it returns the string as is.

The validateNotNull method in the io.nats.client.support.Validator class is a static method that validates whether a given string s is not null.

If the s string is null, it throws an IllegalArgumentException with a message stating that the fieldName (provided as a parameter) cannot be null.

The method returns the same string s if it is not null.

sequence diagram

public static Object validateNotNull(Object o, String fieldName)

public static Object validateNotNull(Object o, String fieldName) {
    if (o == null) {
        throw new IllegalArgumentException(fieldName + " cannot be null");
    }
    return o;
}

Method Description: validateNotNull

This method is defined in the io.nats.client.support.Validator class. It takes in two parameters, an Object o and a String fieldName. The purpose of this method is to validate that the given object is not null.

The method starts by checking if the parameter o is null using the == operator. If the object is indeed null, an IllegalArgumentException is thrown, with the error message constructed by concatenating the fieldName parameter with the string " cannot be null".

If the object is not null, the method simply returns the object.

It is important to note that this method does not modify the object in any way; it is purely used for validation purposes.

The validateNotNull method in the io.nats.client.support.Validator class is used to validate that an object is not null.

The method takes two parameters: o, which is the object to be validated, and fieldName, which is a string representing the name of the field being checked.

If the o parameter is null, the method throws an IllegalArgumentException with a message that includes the fieldName. Otherwise, if the o parameter is not null, the method simply returns the object.

sequence diagram

public static int validateGtZero(int i, String label)

public static int validateGtZero(int i, String label) {
    if (i < 1) {
        throw new IllegalArgumentException(label + " must be greater than zero");
    }
    return i;
}

Method Description

The validateGtZero method, defined in the io.nats.client.support.Validator class, is responsible for validating whether a given integer value is greater than zero.

Method Signature

public static int validateGtZero(int i, String label)

Input Parameters

  • int i: the integer value to be validated
  • String label: the label associated with the integer value, used for error messaging purposes

Output

  • Returns the validated integer value i if it is greater than zero

Behaviour

  1. Check if the value of i is less than 1.
  2. If the above condition is true, throw an IllegalArgumentException with the error message format: label + " must be greater than zero".
  3. If the value of i is greater than zero, return i.

The method validateGtZero defined in class io.nats.client.support.Validator is a static method that takes an integer i and a string label as parameters.

The purpose of this method is to validate that the integer i is greater than zero. If the condition i < 1 is not met, meaning that i is less than or equal to zero, an IllegalArgumentException is thrown with a message stating that the given label should be greater than zero.

If the condition is met and i is greater than zero, the method returns the same integer i.

In summary, the validateGtZero method ensures that the provided integer value is higher than zero, throwing an exception if not, and returning the integer value otherwise.

sequence diagram

public static long validateGtZeroOrMinus1(long l, String label)

public static long validateGtZeroOrMinus1(long l, String label) {
    if (zeroOrLtMinus1(l)) {
        throw new IllegalArgumentException(label + " must be greater than zero or -1 for unlimited");
    }
    return l;
}

Method: validateGtZeroOrMinus1

This method, validateGtZeroOrMinus1, is defined in the io.nats.client.support.Validator class. It takes two parameters: l, which is a long value, and label, which is a String.

Method Description

The purpose of this method is to validate the l value, ensuring that it is either greater than zero or equal to -1. If the l value does not meet this condition, an IllegalArgumentException is thrown with a message indicating that the label must be greater than zero or equal to -1 for unlimited.

Method Signature

public static long validateGtZeroOrMinus1(long l, String label)

Parameters

  • l - the long value that needs to be validated.
  • label - the String label used for generating an error message if the validation fails.

Return Value

  • long - the validated value of l.

Method Body

if (zeroOrLtMinus1(l)) {
    throw new IllegalArgumentException(label + " must be greater than zero or -1 for unlimited");
}
return l;

Step-by-Step Explanation

  1. The method checks if the l value satisfies the condition specified by the zeroOrLtMinus1 method (implementation details not provided). This condition is meant to determine if l is either zero or less than -1.
  2. If the condition is satisfied, an IllegalArgumentException is thrown with an error message stating that the label must be greater than zero or equal to -1 for unlimited.
  3. If the condition is not satisfied, the method returns the original l value.
  4. The method execution completes.

The validateGtZeroOrMinus1 method in the Validator class within the io.nats.client.support package is used to validate if a given long value is greater than zero or equal to -1.

If the value passed as the first argument is equal to or less than zero, an IllegalArgumentException is thrown with a message indicating that the value specified by the label parameter must be greater than zero or -1 for unlimited.

If the value is greater than zero or equal to -1, it is returned as the result of the method.

sequence diagram

public static long validateGtEqMinus1(long l, String label)

public static long validateGtEqMinus1(long l, String label) {
    if (l < -1) {
        throw new IllegalArgumentException(label + " must be greater than zero or -1 for unlimited");
    }
    return l;
}

Method: validateGtEqMinus1

The validateGtEqMinus1 method is defined in the class io.nats.client.support.Validator. It takes in two parameters: l of type long and label of type String.

Step 1: Check if l is less than -1

The method checks if the value of l is less than -1 using the condition l < -1.

Step 2: Throw an exception if l is less than -1

If the value of l is less than -1, an IllegalArgumentException is thrown with the message label + " must be greater than zero or -1 for unlimited". This exception indicates that the label value must be greater than zero or equal to -1 in order to proceed.

Step 3: Return l

If the value of l is greater than or equal to -1, the method simply returns the value of l.

The validateGtEqMinus1 method in the Validator class, defined in the io.nats.client.support package, is used to validate if a given long value is greater than or equal to -1.

The method takes two parameters: l (the long value to be validated) and label (a string indicating the label or name of the value being validated).

Inside the method, it checks if the long value l is less than -1. If it is, an IllegalArgumentException is thrown with a message indicating that the value must be greater than zero or -1 for unlimited.

If the value passes the validation, it is returned without any modifications.

This method ensures that the long value provided is valid and meets the required criteria, helping to maintain data integrity and prevent incorrect usage of the value in the code.

sequence diagram

public static long validateNotNegative(long l, String label)

public static long validateNotNegative(long l, String label) {
    if (l < 0) {
        throw new IllegalArgumentException(label + " cannot be negative");
    }
    return l;
}

validateNotNegative Method

The validateNotNegative method is defined in the io.nats.client.support.Validator class. It takes two parameters: a long value l and a String label.

The purpose of this method is to validate that the provided long value is not negative. It ensures that the value is greater than or equal to zero.

Here is a step-by-step description of what the method does:

  1. Check if the value of l is less than zero:

    • If l is indeed less than zero, it means that the value is negative.
    • In such a case, an IllegalArgumentException is thrown with a message that includes the provided label.
    • The message states that the value cannot be negative.
    • This exception serves as an indicator that the provided value is invalid.
  2. If the value of l is not negative, it means it is valid.

    • The method continues execution and returns the provided value l.

By utilizing this method, you can verify that a given long value is not negative by calling Validator.validateNotNegative and providing the value to validate along with a label for identification.

The validateNotNegative method in the Validator class, defined in the io.nats.client.support package, is responsible for checking if a given long value is not negative.

The method takes two parameters: l, which is the long value to be validated, and label, which is a string label used in the exception message if the value is negative.

If the value of l is less than 0, the method throws an IllegalArgumentException, with the message "label cannot be negative", where label is the provided string label concatenated with the message.

If the value is non-negative, the method simply returns the value.

This method can be used to enforce the constraint that a certain long value should always be non-negative.

sequence diagram

public static long validateGtEqZero(long l, String label)

public static long validateGtEqZero(long l, String label) {
    if (l < 0) {
        throw new IllegalArgumentException(label + " must be greater than or equal to zero");
    }
    return l;
}

The method validateGtEqZero in the io.nats.client.support.Validator class is responsible for validating if a given value is greater than or equal to zero. Here is a step-by-step description of how the method works:

  1. Accept two parameters: l, which is the value to be validated, and label, which is a description of the value being checked.
  2. Check if the value l is less than zero using the condition if (l < 0).
  3. If the value is less than zero, it indicates that the value is invalid.
  4. Throw an IllegalArgumentException with a custom error message. The error message consists of the provided label followed by the string "must be greater than or equal to zero".
  5. If the value is greater than or equal to zero, it indicates that the value is valid.
  6. Return the value l as it has been successfully validated.

This method is useful when you want to ensure that a given value is not negative but is instead greater than or equal to zero. By throwing an exception when the value is invalid, it provides a clear indication of the validation failure and allows for proper error handling in the calling code.

The validateGtEqZero method in the Validator class of the io.nats.client.support package checks if a given long value is greater than or equal to zero.

If the value is less than zero, it throws an IllegalArgumentException with a specific message indicating that the value must be greater than or equal to zero.

Regardless of the comparison result, the method returns the original value.

sequence diagram

// ----------------------------------------------------------------------------------------------------

// Helpers // ---------------------------------------------------------------------------------------------------- public static boolean nullOrEmpty(String s)

// ----------------------------------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------------------------------
public static boolean nullOrEmpty(String s) {
    return s == null || s.trim().length() == 0;
}

The nullOrEmpty method in the io.nats.client.support.Validator class is a static helper method used to check if a given string is either null or empty. It follows the following steps:

  1. Check if the input string s is null.
  2. If s is null, return true to indicate that the string is null or empty.
  3. If s is not null, trim the string using the trim() method.
  4. Use the length() method to get the length of the trimmed string.
  5. Check if the length of the trimmed string is 0.
  6. If the length is 0, return true to indicate that the string is empty.
  7. If the length is greater than 0, return false to indicate that the string is not empty.

Here is the method in code:

public static boolean nullOrEmpty(String s) {
    return s == null || s.trim().length() == 0;
}

This method provides a convenient way to check if a string is null or empty before performing any further processing or validation.

The nullOrEmpty method, defined in the io.nats.client.support.Validator class, is a helper method that checks whether a given string is null or empty.

The method takes a string s as input and returns a boolean value indicating whether the string is null or its trimmed length is 0.

This method is useful for validating string inputs in the context of the Nats client.

sequence diagram

public static boolean notPrintable(String s)

public static boolean notPrintable(String s) {
    for (int x = 0; x < s.length(); x++) {
        char c = s.charAt(x);
        if (c < 33 || c > 126) {
            return true;
        }
    }
    return false;
}

Method: notPrintable

The method notPrintable is defined in the class io.nats.client.support.Validator and is used to determine if a given string contains any non-printable characters.

Signature

public static boolean notPrintable(String s)

Parameters

  • s : A string to be checked for non-printable characters.

Return Value

  • true if the string contains any non-printable characters.
  • false if the string does not contain any non-printable characters.

Steps

  1. Start the loop from x = 0 and continue as long as x is less than the length of the string s.
  2. Get the character at index x from the string s and assign it to the variable c.
  3. Check if the ASCII value of c is less than 33 or greater than 126.
    • If the condition is true, it means that c is a non-printable character.
    • In this case, return true to indicate that the string contains non-printable characters.
  4. If the loop completes without finding any non-printable characters, return false to indicate that the string does not contain any non-printable characters.

The notPrintable method in the Validator class is a static method that takes a string as input and checks whether the string contains any non-printable characters. Non-printable characters are defined as characters with ASCII codes below 33 or above 126.

The method uses a loop to iterate through each character in the input string. If a character is found that falls outside the range of printable ASCII characters, the method returns true, indicating that the string contains non-printable characters. If no non-printable characters are found, the method returns false.

This method can be used to validate input strings and ensure that they only contain printable characters, which are typically characters that can be displayed or printed by most systems and devices.

sequence diagram

public static boolean notPrintableOrHasChars(String s, char[] charsToNotHave)

public static boolean notPrintableOrHasChars(String s, char[] charsToNotHave) {
    for (int x = 0; x < s.length(); x++) {
        char c = s.charAt(x);
        if (c < 33 || c > 126) {
            return true;
        }
        for (char cx : charsToNotHave) {
            if (c == cx) {
                return true;
            }
        }
    }
    return false;
}

Method Description - notPrintableOrHasChars

The notPrintableOrHasChars method is a static method defined in the io.nats.client.support.Validator class. This method takes two parameters:

  • s : A string which needs to be checked for printable characters and the presence of specific characters.
  • charsToNotHave : An array of characters that should not be present in the string s.

The purpose of this method is to determine if the given string s contains any non-printable characters or any of the characters specified in charsToNotHave. The method returns a boolean value indicating if any of these conditions are met.

The method accomplishes this by iterating over each character in the string s using a for loop. Inside the loop, each character is checked against two conditions:

  1. If the character is less than 33 (c < 33) or greater than 126 (c > 126), it is considered a non-printable character. In this case, the method immediately returns true indicating that the string contains non-printable characters.

  2. The character is then compared with each character in the charsToNotHave array using another for-each loop. If a match is found (c == cx), the method returns true indicating that the specific character is present in the string.

If neither of the above conditions is met within the loop, the method continues to the next character until all characters in the string have been checked. If the method reaches this point without returning true, it means that no non-printable or unwanted characters were found in the string, and it returns false.

The notPrintableOrHasChars method, defined in the io.nats.client.support.Validator class, checks if a given string s contains any characters that are not printable or are present in the charsToNotHave array.

Here's a breakdown of the method's behavior:

  1. The method takes two parameters: s (the string to be checked) and charsToNotHave (an array of characters that should not be present in the string).

  2. It iterates over each character in the input string s using a for loop.

  3. For each character, it checks if it is not a printable character (ASCII value less than 33 or greater than 126). If so, it returns true.

  4. It then iterates over each character cx in the charsToNotHave array and checks if the current character c is equal to any of these characters. If a match is found, it returns true.

  5. If none of the non-printable characters or prohibited characters are found in the string, it returns false.

In summary, this method is used to validate whether a given string contains characters that are not printable or are listed in the charsToNotHave array.

sequence diagram

// restricted-term = (A-Z, a-z, 0-9, dash 45, underscore 95)+

public static boolean notRestrictedTerm(String s)

// restricted-term  = (A-Z, a-z, 0-9, dash 45, underscore 95)+
public static boolean notRestrictedTerm(String s) {
    for (int x = 0; x < s.length(); x++) {
        char c = s.charAt(x);
        if (c < '0') {
            // before 0
            if (c == '-') {
                // only dash is accepted
                continue;
            }
            // "not"
            return true;
        }
        if (c < ':') {
            // means it's 0 - 9
            continue;
        }
        if (c < 'A') {
            // between 9 and A is "not restricted"
            return true;
        }
        if (c < '[') {
            // means it's A - Z
            continue;
        }
        if (c < 'a') {
            // before a
            if (c == '_') {
                // only underscore is accepted
                continue;
            }
            // "not"
            return true;
        }
        if (c > 'z') {
            // 122 is z, characters after of them are "not restricted"
            return true;
        }
    }
    return false;
}

notRestrictedTerm method in class io.nats.client.support.Validator

This method is used to check whether a given string contains any characters that are not allowed in a restricted term.

Parameters

  • s - A string which needs to be checked.

Return Type

  • boolean - Returns true if the string contains any characters that are not allowed in a restricted term, otherwise returns false.

Algorithm

  1. Iterate over each character in the given string.
  2. Check the value of the character against certain ASCII values to determine if it is a restricted character.
  3. If the character is before '0' (ASCII value < 48), check if it is '-'. If it is, continue to the next character.
  4. If the character is between '0' and ':' (ASCII values 48-57), it is a digit and is allowed in a restricted term. Continue to the next character.
  5. If the character is between '9' and 'A' (ASCII values 58-65), it is not a restricted character. Return true.
  6. If the character is between 'A' and '[' (ASCII values 65-91), it is a capital letter and is allowed in a restricted term. Continue to the next character.
  7. If the character is between '[' and 'a' (ASCII values 91-97), it is not a restricted character. Return true.
  8. If the character is between 'a' and 'z' (ASCII values 97-123), it is a lowercase letter and is allowed in a restricted term. Continue to the next character.
  9. If the character has an ASCII value greater than 'z' (ASCII value > 122), it is not a restricted character. Return true.
  10. If none of the above conditions are met for any character in the string, return false as it is a restricted term.

Example Usage

String term = "my_Term";
boolean isRestricted = notRestrictedTerm(term);
System.out.println(isRestricted); // Output: false

In the above example, the string "my_Term" is checked using the notRestrictedTerm method. Since all characters in the string are allowed in a restricted term, the method returns false.

The notRestrictedTerm method in the Validator class checks if a given string contains any characters that are not allowed in a restricted term.

The method iterates through each character of the string and checks its value against specific ASCII ranges.

  • If the character is before the numerical range (less than '0'), it returns true, indicating that the string is not a restricted term.
  • If the character is within the numerical range ('0' to '9'), it continues to the next character.
  • If the character is between the numerical range and the uppercase alphabetical range, it returns true.
  • If the character is within the uppercase alphabetical range ('A' to 'Z'), it continues to the next character.
  • If the character is before the lowercase alphabetical range, it returns true.
  • If the character is within the lowercase alphabetical range ('a' to 'z'), it continues to the next character.
  • If the character is after the lowercase alphabetical range (greater than 'z'), it returns true.

If none of these conditions are met after iterating through all characters, the method returns false, indicating that the given string is a valid restricted term.

sequence diagram

// limited-term = (A-Z, a-z, 0-9, dash 45, dot 46, fwd-slash 47, equals 61, underscore 95)+

// kv-key-name = limited-term (dot limited-term)* public static boolean notNonWildcardKvKey(String s)

// limited-term = (A-Z, a-z, 0-9, dash 45, dot 46, fwd-slash 47, equals 61, underscore 95)+
// kv-key-name = limited-term (dot limited-term)*
public static boolean notNonWildcardKvKey(String s) {
    if (s.charAt(0) == '.') {
        // can't start with dot
        return true;
    }
    for (int x = 0; x < s.length(); x++) {
        char c = s.charAt(x);
        if (c < '0') {
            // before 0
            if (c == '-' || c == '.' || c == '/') {
                // only dash dot and fwd slash are accepted
                continue;
            }
            // "not"
            return true;
        }
        if (c < ':') {
            // means it's 0 - 9
            continue;
        }
        if (c < 'A') {
            if (c == '=') {
                // equals is accepted
                continue;
            }
            // between 9 and A is "not limited"
            return true;
        }
        if (c < '[') {
            // means it's A - Z
            continue;
        }
        if (c < 'a') {
            // before a
            if (c == '_') {
                // only underscore is accepted
                continue;
            }
            // "not"
            return true;
        }
        if (c > 'z') {
            // 122 is z, characters after of them are "not limited"
            return true;
        }
    }
    return false;
}

The notNonWildcardKvKey method in the io.nats.client.support.Validator class is used to validate a string s to determine if it is a valid key for a key-value pair in a limited-term format. Here is a step-by-step description of what the method is doing based on its body:

  1. The method starts by checking if the first character of the string is a dot (.). If it is, the method returns true indicating that the key cannot start with a dot.

  2. The method then enters a for loop to iterate over each character in the string.

  3. Within the loop, the method checks the value of the current character c.

  4. If c is less than the character '0', it means that c comes before the numbers 0-9. In this case, the method checks if c is equal to dash (-), dot (.), or forward slash (/) and if it is, it continues to the next character. If c is not one of these characters, the method returns true, indicating that the key contains a character that is not allowed before the numbers 0-9.

  5. If c is between the characters '0' and '9', the method continues to the next character because it is a valid digit in the key.

  6. If c is less than the character 'A', it means that c comes between the numbers 9 and the uppercase letters A-Z. In this case, the method checks if c is equal to equal sign (=) and if it is, it continues to the next character. If c is not an equal sign, the method returns true, indicating that the key contains a character that is not allowed between the numbers 9 and the uppercase letters A-Z.

  7. If c is between the characters 'A' and 'Z', the method continues to the next character because it is a valid uppercase letter in the key.

  8. If c is less than the character 'a', it means that c comes between the uppercase letters A-Z and the lowercase letters a-z. In this case, the method checks if c is equal to underscore (_) and if it is, it continues to the next character. If c is not an underscore, the method returns true, indicating that the key contains a character that is not allowed between the uppercase letters A-Z and the lowercase letters a-z.

  9. If c is greater than the character 'z', it means that c comes after the lowercase letters a-z. In this case, the method returns true, indicating that the key contains a character that is not allowed after the lowercase letters a-z.

  10. After iterating over all the characters in the string and not encountering any invalid characters, the method returns false, indicating that the key is valid.

This method can be used to validate whether a string is a valid key for a key-value pair in a limited-term format.

The notNonWildcardKvKey method is a static method defined in the Validator class of the io.nats.client.support package. It takes a string s as an input and returns a boolean value.

This method verifies if the input string s is a valid key for a key-value store based on specific criteria. The criteria for a valid key are that it must start with a character other than a dot (.), and can only contain alphanumeric characters (A-Z, a-z, 0-9), dash (-), dot (.), forward slash (/), equals (=), and underscore (_).

The method checks each character of the input string against these criteria using a series of if statements. If any character does not meet the criteria, the method returns true, indicating that the key is not valid. If all characters pass the criteria, the method returns false, indicating that the key is valid.

sequence diagram

// (A-Z, a-z, 0-9, star 42, dash 45, dot 46, fwd-slash 47, equals 61, gt 62, underscore 95)+

public static boolean notWildcardKvKey(String s)

// (A-Z, a-z, 0-9, star 42, dash 45, dot 46, fwd-slash 47, equals 61, gt 62, underscore 95)+
public static boolean notWildcardKvKey(String s) {
    if (s.charAt(0) == '.') {
        // can't start with dot
        return true;
    }
    for (int x = 0; x < s.length(); x++) {
        char c = s.charAt(x);
        if (c < '0') {
            // before 0
            if (c == '*' || c == '-' || c == '.' || c == '/') {
                // only star dash dot and fwd slash are accepted
                continue;
            }
            // "not"
            return true;
        }
        if (c < ':') {
            // means it's 0 - 9
            continue;
        }
        if (c < 'A') {
            if (c == '=' || c == '>') {
                // equals, gt is accepted
                continue;
            }
            // between 9 and A is "not limited"
            return true;
        }
        if (c < '[') {
            // means it's A - Z
            continue;
        }
        if (c < 'a') {
            // before a
            if (c == '_') {
                // only underscore is accepted
                continue;
            }
            // "not"
            return true;
        }
        if (c > 'z') {
            // 122 is z, characters after of them are "not limited"
            return true;
        }
    }
    return false;
}

Method Description: notWildcardKvKey

This method, notWildcardKvKey, is defined in class io.nats.client.support.Validator. It takes a string s as input and checks if the string represents a valid key for a key-value pair.

Step-by-step Description:

  1. Check if the first character of the input string s is a period (.).

    • If it is, return true as keys cannot start with a dot.
  2. Iterate through each character c in the input string s.

    • For each character:
      • If it is less than the character '0':
        • Check if it is one of the allowed characters: '*', '-', '.', '/'.
          • If it is, continue to the next character.
          • If it is not, return true as only the allowed characters are accepted before '0'.
      • If it is less than the character ':' and greater than or equal to character '0', continue to the next character as it is a number (0-9).
      • If it is less than character 'A' and greater than character '9':
        • Check if it is one of the allowed characters: '=', '>'.
          • If it is, continue to the next character.
          • If it is not, return true as only the allowed characters are accepted between '9' and 'A'.
      • If it is less than character '[' and greater than or equal to character 'A', continue to the next character as it is an uppercase letter (A-Z).
      • If it is less than character 'a' and greater than character 'A':
        • Check if it is the allowed character '_'.
          • If it is, continue to the next character.
          • If it is not, return true as only the allowed character '_' is accepted before lowercase letters.
      • If it is greater than character 'z' (122 is the ASCII value of 'z'), return true as characters after 'z' are not limited.
  3. If none of the above conditions are met, return false as the input string s represents a valid key for a key-value pair.

Note: The method follows a pattern-based validation where the characters in the input string are checked against specific ranges and allowed characters. Any character found outside the allowed ranges or characters will result in the method returning true, indicating that the input string is not a valid key.

The notWildcardKvKey method, defined in the Validator class of the io.nats.client.support package, is used to validate a key string for a key-value pair.

The method checks if the given string contains characters that follow the specified pattern, which includes uppercase letters (A-Z), lowercase letters (a-z), numbers (0-9), special characters like star (*), dash (-), dot (.), forward slash (/), equals (=), and greater than (>). The string can also contain an underscore (_) character.

The method ensures that the string does not start with a dot (.), as that is not allowed. It also performs checks for specific characters based on their ASCII values, rejecting any characters that do not meet the allowed criteria.

If the string meets the criteria, the method returns false, indicating that it is a valid key. If the string does not meet the criteria or violates the specified pattern, the method returns true, indicating that it is not a valid key.

sequence diagram

public static String validateSemVer(String s, String label, boolean required)

public static String validateSemVer(String s, String label, boolean required) {
    return _validate(s, required, label, () -> {
        if (!isSemVer(s)) {
            throw new IllegalArgumentException(label + " must be a valid SemVer");
        }
        return s;
    });
}

The validateSemVer method, defined in the io.nats.client.support.Validator class, is used to validate a string representing a Semantic Version (SemVer) number. Here is a step-by-step description of what the method does:

  1. The method takes three parameters: s (the string to be validated), label (a label used for error messages), and required (a boolean value indicating whether the string is required or not).

  2. The method calls a private static method _validate and passes the s, required, label, and a lambda expression as arguments. The lambda expression is used to define the behavior in case of successful validation.

  3. The _validate method performs the actual validation by checking if the string s is a valid SemVer number. If it is not, an IllegalArgumentException is thrown with an error message containing the label and the requirement that the value must be a valid SemVer number.

  4. If the validation passes and the string is a valid SemVer number, the lambda expression defined in the _validate method is executed. This lambda expression returns the validated string s.

  5. Finally, the validateSemVer method returns the validated string s as the result of the method call.

In summary, the validateSemVer method validates a string representation of a Semantic Version number by calling the _validate method, which performs the actual validation and throws an exception if the string is not a valid SemVer number. If the validation passes, the method returns the validated string.

The validateSemVer method in the Validator class is used to validate a given string s as a Semantic Version (SemVer) according to the SemVer specification.

The method takes three parameters:

  • s - the string to be validated as a SemVer.
  • label - a label or identifier for the string being validated.
  • required - a boolean flag indicating whether the validated string is required or not.

The method internally calls a private _validate method, passing the required parameters along with a lambda expression that performs the actual validation. If the provided string s is not a valid SemVer, an IllegalArgumentException is thrown, with a specific error message indicating that the provided label must be a valid SemVer.

If the provided string s is valid according to the SemVer specification, it is returned as the result of the method.

sequence diagram

public static boolean listsAreEqual(List l1, List l2, boolean nullSecondEqualsEmptyFirst)

public static <T> boolean listsAreEqual(List<T> l1, List<T> l2, boolean nullSecondEqualsEmptyFirst) {
    if (l1 == null) {
        return l2 == null;
    }
    if (l2 == null) {
        return nullSecondEqualsEmptyFirst && l1.size() == 0;
    }
    return l1.equals(l2);
}

The listsAreEqual method, defined in the io.nats.client.support.Validator class, compares two lists - l1 and l2 - to determine if they are equal. Here is a step-by-step description of what the method is doing:

  1. Check if l1 is null:
  • If l1 is null, proceed to step 2.
  • If l1 is not null, proceed to step 3.
  1. Check if l2 is also null:
  • If l2 is null, return true, indicating that both lists are null and therefore equal.
  • If l2 is not null, return false, indicating that l1 is null but l2 is not, so they are not equal.
  1. Check if l2 is null:
  • If l2 is null and nullSecondEqualsEmptyFirst is true, check if l1 is empty (i.e., it has a size of 0).
    • If l1 is empty, return true, indicating that both lists are empty and therefore equal.
    • If l1 is not empty, return false, indicating that l1 is not empty but l2 is, so they are not equal.
  • If l2 is not null, proceed to step 4.
  1. Use the equals() method to compare the contents of l1 and l2:
  • If the contents of l1 and l2 are equal, return true.
  • If the contents of l1 and l2 are not equal, return false.

Note: The equals() method used in step 4 will use the implementation of equals() provided by the elements in the lists l1 and l2.

The method listsAreEqual is a static method defined in the Validator class in the io.nats.client.support package.

This method takes two generic lists (l1 and l2) as inputs and a boolean flag (nullSecondEqualsEmptyFirst). It compares the equality of the two lists based on the following logic:

  1. If the first list (l1) is null, the method checks if the second list (l2) is also null. If yes, it returns true, indicating that both lists are equal. If the second list is not null, it returns false, indicating that the lists are not equal.

  2. If the first list (l1) is not null but the second list (l2) is null, the method checks if the nullSecondEqualsEmptyFirst flag is set to true and if the size of the first list is 0. If both conditions are met, it returns true, indicating that the lists are equal. Otherwise, it returns false.

  3. If both lists are not null, the method uses the equals method of the first list (l1) to compare it with the second list (l2). If the lists are equal, it returns true. Otherwise, it returns false.

In summary, this method checks the equality of two lists, taking into account potential null lists and the option to treat a null second list as equal to an empty first list.

public static boolean mapsAreEqual(Map<String, String> m1, Map<String, String> m2, boolean nullSecondEqualsEmptyFirst)

public static boolean mapsAreEqual(Map<String, String> m1, Map<String, String> m2, boolean nullSecondEqualsEmptyFirst) {
    if (m1 == null) {
        return m2 == null;
    }
    if (m2 == null) {
        return nullSecondEqualsEmptyFirst && m1.size() == 0;
    }
    if (m1.size() != m2.size()) {
        return false;
    }
    for (Map.Entry<String, String> entry : m1.entrySet()) {
        if (!entry.getValue().equals(m2.get(entry.getKey()))) {
            return false;
        }
    }
    return true;
}

mapsAreEqual Method - Explanation

The mapsAreEqual method is defined in the io.nats.client.support.Validator class. It takes in two Map<String, String> objects (m1 and m2) and a boolean flag (nullSecondEqualsEmptyFirst).

The purpose of this method is to compare two maps for equality. It returns true if the maps are equal and false otherwise.

Here is a step-by-step breakdown of what the method is doing:

  1. If m1 is null, it checks if m2 is also null. If true, it means both maps are null and returns true. If m2 is not null, it returns false because they are not equal.

  2. If m1 is not null, it checks if m2 is null. If true, it checks the value of the nullSecondEqualsEmptyFirst flag. If the flag is true and the size of m1 is 0, it means the second map is considered as an empty map, and it returns true. Otherwise, it returns false.

  3. If both m1 and m2 are not null, it checks if the sizes of the two maps are equal. If they are not equal, it returns false.

  4. If the sizes of both maps are equal, it iterates through each entry in m1.

  5. For each entry, it retrieves the corresponding value from m2 using the key. If the value is not equal to the value in m1, it means the maps are not equal, and it returns false.

  6. If all entries in m1 have been checked and they are equal to their corresponding values in m2, the method returns true indicating that the maps are equal.

The mapsAreEqual method, defined in the io.nats.client.support.Validator class, is used to compare two maps (m1 and m2) and determine if they are equal.

The method takes three parameters:

  • m1: The first map to compare.
  • m2: The second map to compare.
  • nullSecondEqualsEmptyFirst: A boolean flag indicating whether a null second map should be considered equal to an empty first map.

The method first checks if m1 is null. If it is, the method returns true if m2 is also null, and false otherwise.

Next, it checks if m2 is null. If it is and nullSecondEqualsEmptyFirst is true, the method returns true if m1 is also empty (i.e., has a size of 0), and false otherwise.

If both maps are not null, the method checks if their sizes are equal. If they are not, the method returns false.

Finally, the method iterates over the entries of m1 using a for-each loop. For each entry, it compares the value in m1 to the corresponding value in m2 based on the key. If any pair of values are not equal, the method returns false. If all pairs are equal, the method returns true.

In summary, the mapsAreEqual method compares two maps, accounting for null maps and specifying whether a null second map should be considered equal to an empty first map. It returns true if the maps are equal and false otherwise.

sequence diagram

SSLUtils

SSLUtils

The SSLUtils class is a public class that provides utilities for working with SSL (Secure Sockets Layer) in software engineering. It includes methods and functionalities for managing SSL certificates, configuring SSL connections, and handling SSL exceptions. This class is designed to facilitate secure communication over network sockets using SSL protocols.

public static SSLContext createOpenTLSContext()

public static SSLContext createOpenTLSContext() {
    SSLContext context = null;
    try {
        context = SSLContext.getInstance(Options.DEFAULT_SSL_PROTOCOL);
        context.init(null, trustAllCerts, SRAND);
    } catch (Exception e) {
        context = null;
    }
    return context;
}

The createOpenTLSContext method in the SSLUtils class is used to create an SSLContext object for establishing a secure TLS connection.

Here is a step-by-step description of what the method does:

  1. It declares a variable context of type SSLContext and initializes it to null.
  2. It tries to create an SSLContext object using the getInstance method from the SSLContext class, passing in the value of Options.DEFAULT_SSL_PROTOCOL.
    • Options.DEFAULT_SSL_PROTOCOL typically specifies the default SSL/TLS protocol version to be used, such as "TLSv1.2".
  3. It initializes the SSLContext object context by calling its init method, passing in the following parameters:
    • null as the first parameter, indicating that no KeyManager should be used.
    • trustAllCerts as the second parameter, indicating that all server certificates should be trusted.
    • SRAND as the third parameter, which is a SecureRandom object used for seed generation in the handshake process.
    • trustAllCerts is likely an array of TrustManager objects that implement a trust manager that trusts all certificates.
    • SRAND is likely a SecureRandom object that provides a cryptographically strong random number generator.
  4. If any exception occurs during the creation or initialization of the SSLContext object, the context variable is set back to null.
  5. Finally, the method returns the SSLContext object context, which may be null if any exception occurred.

Overall, the createOpenTLSContext method attempts to create and initialize an SSLContext object with the default SSL/TLS protocol and with trust in all server certificates. It is typically used for establishing a secure TLS connection in the NATS Java client library.

The createOpenTLSContext method in the SSLUtils class is used to create an SSLContext object for establishing a TLS connection.

Inside the method, it first calls SSLContext.getInstance method to create an SSLContext object with the default SSL protocol specified in the Options class.

Then, it initializes the SSLContext object by calling the init method with null as the TrustManager array, trustAllCerts as the TrustManager implementation (presumably, an array of all-trusting trust managers), and SRAND as the source of randomness.

If any exception occurs during the creation or initialization process, the SSLContext object will be set to null.

Finally, the method returns the created SSLContext object.

Overall, this method is responsible for creating and initializing an SSLContext object for TLS connections with the default SSL protocol.

sequence diagram

DateTimeUtils

DateTimeUtils

This class, DateTimeUtils, is an abstract class that provides internal json parsing helpers.

public static ZonedDateTime parseDateTime(String dateTime, ZonedDateTime dflt)

public static ZonedDateTime parseDateTime(String dateTime, ZonedDateTime dflt) {
    try {
        return toGmt(ZonedDateTime.parse(dateTime));
    } catch (DateTimeParseException s) {
        return dflt;
    }
}

Method Description: parseDateTime

The parseDateTime method is defined in the io.nats.client.support.DateTimeUtils class and is responsible for parsing a given dateTime string and returning a ZonedDateTime object. If the parsing fails, the method will return a default ZonedDateTime object specified by the dflt parameter.

Parameters:

  • dateTime (String): The dateTime string to be parsed.
  • dflt (ZonedDateTime): The default ZonedDateTime object to be returned if parsing fails.

Return Value:

  • ZonedDateTime: A ZonedDateTime object representing the parsed date and time. If parsing fails, the default ZonedDateTime object will be returned.

Method Steps:

  1. Try to execute the following steps:

    • Parse the dateTime string using the ZonedDateTime.parse method.
    • Convert the parsed ZonedDateTime object to GMT time zone using the toGmt method.
    • Return the converted ZonedDateTime object.
  2. If any DateTimeParseException occurs during the parsing process:

    • Catch the exception.
    • Return the default ZonedDateTime object specified by the dflt parameter.

The parseDateTime method in the DateTimeUtils class is a static method that takes a string representing a date and time, and returns a ZonedDateTime object. If the string cannot be parsed into a ZonedDateTime, it returns a default value provided as a parameter.

The method attempts to parse the dateTime string using the ZonedDateTime.parse method. If the parsing is successful, the resulting ZonedDateTime object is converted to GMT using the toGmt method (which is not shown in the code snippet). If the parsing fails and throws a DateTimeParseException, the method returns the default value dflt.

sequence diagram

WebsocketOutputStream

WebsocketOutputStream

The WebsocketOutputStream class is a public class that extends the OutputStream class. This class is used to handle output stream operations for websockets.

@Override

public void close() throws IOException

@Override
public void close() throws IOException {
    // NOTE: Per spec, we should technically wait to receive the close frame,
    // but we are not in control of the InputStream here...
    WebsocketFrameHeader header = new WebsocketFrameHeader().withOp(OpCode.CLOSE, true).withNoMask().withPayloadLength(0);
    int length = header.read(headerBuffer, 0, headerBuffer.length);
    wrap.write(headerBuffer, 0, length);
    wrap.close();
}

The close method in the WebsocketOutputStream class, defined in the io.nats.client.support package, is used to close the output stream for a WebSocket connection.

Here are the step-by-step description of what this method does:

  1. The method overrides the close method from the superclass, which is java.io.OutputStream, and it throws an IOException.

  2. Before closing the output stream, the method makes a note that, as per the WebSocket specification, ideally, it should wait to receive the close frame. However, since it is not in control of the input stream, it doesn't wait.

  3. It creates a new instance of the WebsocketFrameHeader class.

  4. The WebsocketFrameHeader instance is configured with the OpCode.CLOSE operation code, indicating that it wants to close the WebSocket connection. The second parameter true sets the "final" bit of the frame header to true, indicating that this frame represents the entire payload.

  5. The WebsocketFrameHeader instance is further configured with the withNoMask method, which disables the masking of the payload. Masking is a security feature to prevent certain attacks, but in this case, it is not required, so it is disabled.

  6. The payload length is set to 0 because it is an empty frame.

  7. The header object reads the frame header data into a byte array called headerBuffer using the read method, which returns the length of the read data.

  8. The wrap object, which represents the underlying output stream, writes the headerBuffer data to the stream using the write method. The length parameter specifies the number of bytes to write.

  9. Finally, the wrap object's close method is called to close the underlying output stream, releasing any system resources associated with it.

Overall, this close method sends a close frame header with no payload length to indicate the intention to close the WebSocket connection and then closes the output stream.

The close method in the io.nats.client.support.WebsocketOutputStream class is responsible for closing the WebSocket output stream.

In the method, it first creates a WebSocket frame header with the CLOSE opcode and no payload. It then writes the header to the underlying output stream using the write method of the wrap object. Finally, it closes the wrap object, which will flush any remaining data and close the output stream.

It is important to note that according to the WebSocket specification, the method should technically wait to receive the close frame, but that is not possible in this context because the method has no control over the underlying input stream.

sequence diagram

@Override

public void write(byte[] buffer, int offset, int length) throws IOException

@Override
public void write(byte[] buffer, int offset, int length) throws IOException {
    header.withPayloadLength(length);
    if (masked) {
        header.withMask(random.nextInt());
    }
    int headerBufferOffset = header.read(headerBuffer, 0, headerBuffer.length);
    int consumed = Math.min(length, headerBuffer.length - headerBufferOffset);
    System.arraycopy(buffer, offset, headerBuffer, headerBufferOffset, consumed);
    header.filterPayload(headerBuffer, headerBufferOffset, consumed);
    wrap.write(headerBuffer, 0, headerBufferOffset + consumed);
    if (consumed < length) {
        // NOTE: We could perform a "mark" operation before filtering the
        // payload which saves the payloadLength and maskingKeyOffset, then
        // perform a "resetMark" operation after writing the masked buffer
        // and finally re-applying the filter in order to preserve the
        // original values of the bytes. However, there appears to be no
        // code which relies on the bytes in the buffer to be preserved,
        // so we are keeping things efficient by not performing these
        // operations.
        header.filterPayload(buffer, offset + consumed, length - consumed);
        wrap.write(buffer, offset + consumed, length - consumed);
    }
}

Method Description

The write(byte[] buffer, int offset, int length) method, defined in the WebsocketOutputStream class, is responsible for writing the specified portion of a byte array to the underlying output stream.

Steps:

  1. Set the length of the payload in the header.
  2. If the payload is masked, generate a random mask and set it in the header.
  3. Read the header into a buffer and calculate the offset.
  4. Calculate the number of bytes to be consumed, which is the minimum of the length and the remaining space in the header buffer.
  5. Copy the bytes from the input buffer to the header buffer.
  6. Filter the payload bytes in the header buffer.
  7. Write the header buffer to the underlying output stream.
  8. If the number of consumed bytes is less than the length of the payload:
    • Filter the remaining payload bytes.
    • Write the remaining payload bytes to the underlying output stream.

The write method in the WebsocketOutputStream class is used to write data to a WebSocket connection.

This method takes in three parameters: buffer, offset, and length. The buffer parameter is the array of bytes to be written, the offset parameter is the starting index of the data to be written in the buffer, and the length parameter is the number of bytes to be written.

Within the method, the payloadLength of the WebSocket header is updated with the length of the data to be written. If the WebSocket is masked, a random mask value is generated and added to the header.

A portion of the data is then copied from the buffer to a headerBuffer, which is a buffer for the WebSocket header. The data in the headerBuffer is then filtered according to the WebSocket payload filtering rules.

After that, the filtered headerBuffer is written to the WebSocket connection using the wrap.write method.

If there is still remaining data in the original buffer after writing the headerBuffer, it is filtered and then written to the WebSocket connection using the wrap.write method again.

Note: There is a comment indicating that a more complex "mark" and "resetMark" operation could be performed to preserve the original values of the bytes in the buffer, but it is mentioned that there is no code relying on this preservation, so the more efficient approach is taken.

sequence diagram

WebSocket

WebSocket

The WebSocket class is a public class that extends the Socket class. It provides functionality for handling communication over a WebSocket connection.

private static void handshake(Socket socket, String host, List<Consumer> interceptors) throws IOException

private static void handshake(Socket socket, String host, List<Consumer<HttpRequest>> interceptors) throws IOException {
    InputStream in = socket.getInputStream();
    OutputStream out = socket.getOutputStream();
    HttpRequest request = new HttpRequest();
    // The value of this header field MUST be a
    // nonce consisting of a randomly selected 16-byte value that has
    // been base64-encoded
    byte[] keyBytes = new byte[16];
    new SecureRandom().nextBytes(keyBytes);
    String key = Base64.getEncoder().encodeToString(keyBytes);
    request.getHeaders().add("Host", host).add("Upgrade", "websocket").add("Connection", "Upgrade").add("Sec-WebSocket-Key", key).add("Sec-WebSocket-Protocol", "nats").add("Sec-WebSocket-Version", "13");
    // TODO: Support Sec-WebSocket-Extensions: permessage-deflate
    // TODO: Support Nats-No-Masking: TRUE
    for (Consumer<HttpRequest> interceptor : interceptors) {
        interceptor.accept(request);
    }
    out.write(request.toString().getBytes(UTF_8));
    // rfc6455 4.1 "The client MUST validate the server's response as follows:"
    byte[] buffer = new byte[MAX_LINE_LEN];
    String responseLine = readLine(buffer, in);
    if (null == responseLine) {
        throw new IllegalStateException("Expected HTTP response line not to exceed " + MAX_LINE_LEN);
    }
    // 1. expect 101:
    if (!responseLine.toLowerCase().startsWith(WEBSOCKET_RESPONSE_LINE.toLowerCase())) {
        throw new IllegalStateException("Expected " + WEBSOCKET_RESPONSE_LINE + ", but got " + responseLine);
    }
    Map<String, String> headers = new HashMap<>();
    while (true) {
        String line = readLine(buffer, in);
        if (null == line) {
            throw new IllegalStateException("Expected HTTP header to not exceed " + MAX_LINE_LEN);
        }
        if ("".equals(line)) {
            break;
        }
        int colon = line.indexOf(':');
        if (colon >= 0) {
            if (headers.size() >= MAX_HTTP_HEADERS) {
                throw new IllegalStateException("Exceeded max HTTP headers=" + MAX_HTTP_HEADERS);
            }
            headers.put(line.substring(0, colon).trim().toLowerCase(), line.substring(colon + 1).trim());
        } else {
            throw new IllegalStateException("Expected HTTP header to contain ':', but got " + line);
        }
    }
    // 2. Expect `Upgrade: websocket`
    if (!"websocket".equalsIgnoreCase(headers.get("upgrade"))) {
        throw new IllegalStateException("Expected HTTP `Upgrade: websocket` header");
    }
    // 3. Expect `Connection: Upgrade`
    if (!"upgrade".equalsIgnoreCase(headers.get("connection"))) {
        throw new IllegalStateException("Expected HTTP `Connection: Upgrade` header");
    }
    // 4. Sec-WebSocket-Accept: base64(sha1(key + "258EAF..."))
    MessageDigest sha1;
    try {
        sha1 = MessageDigest.getInstance("SHA-1");
    } catch (NoSuchAlgorithmException ex) {
        throw new IllegalStateException(ex);
    }
    sha1.update(key.getBytes(UTF_8));
    sha1.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(UTF_8));
    String acceptKey = Base64.getEncoder().encodeToString(sha1.digest());
    String gotAcceptKey = headers.get("sec-websocket-accept");
    if (!acceptKey.equals(gotAcceptKey)) {
        throw new IllegalStateException("Expected HTTP `Sec-WebSocket-Accept: " + acceptKey + ", but got " + gotAcceptKey);
    }
    // 5 & 6 are not valid, since nats-server doesn't
    // implement extensions or protocols.
}

Method Handshake

The handshake method is defined in the io.nats.client.support.WebSocket class, and it is responsible for establishing a WebSocket connection between the client and the server.

Step 1: Set up the request

  1. Create an input stream from the socket to receive data from the server.
  2. Create an output stream from the socket to send data to the server.
  3. Create an instance of HttpRequest.
  4. Generate a 16-byte random value and encode it in base64 format to create a nonce.
  5. Set the necessary headers in the request, including "Host", "Upgrade", "Connection", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol", and "Sec-WebSocket-Version".
  6. Optionally, support additional headers using the provided interceptors.
  7. Convert the request into a byte array and write it to the output stream.

Step 2: Validate the server's response

  1. Define a byte buffer to read data from the input stream.
  2. Read the response line from the input stream.
  3. Ensure that the response line does not exceed the maximum line length.
  4. Verify that the response line starts with "HTTP/1.1 101" to indicate a successful upgrade to WebSocket.
  5. Create a map to store the HTTP headers.
  6. Read each header line from the input stream until an empty line is encountered.
  7. Ensure that each header line does not exceed the maximum line length.
  8. Split each header line by the colon (":") character to separate the header name and value.
  9. Store the header name and value in the map, converting the header name to lowercase.
  10. Ensure that the number of headers does not exceed the maximum allowed limit.

Step 3: Validate the necessary headers

  1. Verify that the "Upgrade" header is set to "websocket".
  2. Verify that the "Connection" header is set to "Upgrade".

Step 4: Validate the Sec-WebSocket-Accept header

  1. Create an instance of MessageDigest using the SHA-1 algorithm.
  2. Update the digest with the base64-encoded nonce and a constant string.
  3. Generate the expected accept key by encoding the digest into base64 format.
  4. Retrieve the received accept key from the headers.
  5. Ensure that the received accept key matches the expected accept key.

Step 5: Not applicable for this implementation

The server does not support Sec-WebSocket-Extensions or Sec-WebSocket-Protocol, so these steps are skipped.

Step 6: Not applicable for this implementation

The server does not support Sec-WebSocket-Extensions or Sec-WebSocket-Protocol, so these steps are skipped.

The handshake method in the io.nats.client.support.WebSocket class is responsible for performing the handshake process between the client and server when establishing a WebSocket connection.

Here is a breakdown of what the method does:

  1. Creates an HttpRequest object and sets the necessary headers for the handshake.
  2. Invokes any interceptors that have been registered with the method.
  3. Writes the request string to the output stream of the socket.
  4. Reads the response line from the input stream and checks that it starts with the expected response code "101".
  5. Parses the HTTP headers from the response and checks that the "Upgrade" and "Connection" headers are set to "websocket" and "upgrade" respectively.
  6. Calculates the accept key for the "Sec-WebSocket-Accept" header by hashing the generated key with a predefined value and encoding it to Base64.
  7. Verifies that the received "Sec-WebSocket-Accept" header value matches the calculated accept key.
  8. Performs additional checks that are not currently used by the nats-server implementation.

Overall, the handshake method ensures that the server accepts the WebSocket connection by validating the response and headers received during the handshake process.

sequence diagram

private static String readLine(byte[] buffer, InputStream in) throws IOException

private static String readLine(byte[] buffer, InputStream in) throws IOException {
    int offset = 0;
    int lastCh = -1;
    while (true) {
        int ch = in.read();
        switch(ch) {
            case -1:
                // Premature EOF (everything should be terminated with \n)
                return new String(buffer, 0, offset, StandardCharsets.ISO_8859_1);
            case '\n':
                // Found \n, remove \r if it is there:
                return new String(buffer, 0, '\r' == lastCh ? offset - 1 : offset, StandardCharsets.ISO_8859_1);
        }
        // Line length exceeded:
        if (offset >= buffer.length) {
            return null;
        }
        buffer[offset++] = (byte) ch;
        lastCh = ch;
    }
}

The readLine method in the WebSocket class is used to read a line from an input stream. It takes a byte array called buffer and an input stream called in as parameters.

Here is a step-by-step description of what the method does:

  1. Initialize variables:

    • offset is set to 0, which represents the current index in the buffer array.
    • lastCh is set to -1, which represents the last character read from the input stream.
  2. Enter an infinite loop:

    • This loop will continue until the method explicitly returns a value.
  3. Read a character from the input stream:

    • The in.read() method is called to read the next character from the input stream.
    • The character is stored in the variable ch.
  4. Process the character:

    • The method uses a switch statement to check the value of ch.

    • If ch is -1:

      • This indicates that the end of the input stream has been reached (premature EOF).
      • The method constructs a new string using the buffer array, from index 0 to offset, using the ISO-8859-1 character encoding.
      • The constructed string is returned as the result of the method.
    • If ch is '\n' (newline character):

      • This indicates that a complete line has been read.
      • The method constructs a new string using the buffer array, from index 0 to offset, using the ISO-8859-1 character encoding.
      • If the last character read (lastCh) is '\r' (carriage return character), it means that the line might contain a Windows-style line ending.
        • In this case, the method subtracts 1 from offset to remove the '\r' character from the line.
      • The constructed string is returned as the result of the method.
    • If none of the above conditions are met (line length exceeded):

      • The method checks if the offset is greater than or equal to the length of the buffer array.
      • If the condition is true, the method returns null to indicate that the line length has exceeded the buffer size.
  5. Store the read character in the buffer array:

    • The read character is cast to a byte and stored in the buffer array at the current offset index.
    • The offset is then incremented.
  6. Update the lastCh variable:

    • The lastCh variable is updated with the value of the current character (ch).
  7. Repeat the loop to read the next character from the input stream.

Note: The method assumes that the input stream contains lines terminated with either '\n' or '\r\n' characters.

The readLine method is used to read a line of text from an input stream in the context of a WebSocket. It takes in a byte[] buffer and an InputStream as parameters.

The method reads characters from the input stream until it encounters either the end of the stream or a line break character ('\n'). If it reaches the end of the stream, it returns the contents of the buffer as a string.

If it encounters a line break character, it checks if the previous character was a carriage return character ('\r'). If so, it removes it from the buffer before returning the contents as a string.

If the line length exceeds the size of the buffer, the method returns null.

The method uses the StandardCharsets.ISO_8859_1 character encoding when converting the buffer to a string.

sequence diagram

RandomUtils

RandomUtils

The RandomUtils class is an abstract class that provides various utility methods for generating random values. It is designed to be extended by concrete classes, which can then access these random utility methods to generate random numbers, strings, and other types of values. This class serves as a convenient tool for developers who need to incorporate randomization into their software applications.

public static long nextLong(Random rng, long maxValue)

public static long nextLong(Random rng, long maxValue) {
    // error checking and 2^x checking removed for simplicity.
    long bits;
    long val;
    do {
        bits = (rng.nextLong() << 1) >>> 1;
        val = bits % maxValue;
    } while (bits - val + (maxValue - 1) < 0L);
    return val;
}

nextLong Method Description

The nextLong method, defined in the io.nats.client.support.RandomUtils class, generates a random long integer value within a specified range.

Method Signature

public static long nextLong(Random rng, long maxValue)

Parameters

  • rng: A Random object used for generating random numbers.
  • maxValue: The upper bound (exclusive) of the range within which the random long value should be generated.

Method Steps

  1. Error checking and checking whether maxValue is a power of 2 are removed for simplicity.
  2. Declare two long variables, bits and val, to store the generated random bits and the final random value, respectively.
  3. Start a do-while loop that will run until a suitable random value is found.
  4. Generate random bits using the nextLong() method of the rng object and store them in the bits variable.
  5. Shift the bits one position to the left and then one position back to the right using the bitwise left shift (<<) and the bitwise right shift (>>>) operators, respectively. This operation is performed to ensure that the bits value is non-negative (signed shift right operator preserves the sign bit).
  6. Calculate the remainder of dividing bits by maxValue and store it in the val variable. This will give a random value within the range [0, maxValue).
  7. Check if the difference between bits, val, and maxValue - 1 is less than 0L. If the condition is true, it means that the generated value is larger than maxValue - 1, which would create a bias towards smaller values. In this case, the loop repeats to generate a new random value.
  8. If the condition in step 7 is false, the loop is exited, and the val variable containing the randomly generated value is returned as the result of the method.

The method nextLong in the class io.nats.client.support.RandomUtils generates a pseudo-random long value within a specified range.

The method takes two parameters: rng, which is an instance of the Random class used to generate the random values, and maxValue, which represents the upper bound of the range (exclusive).

Inside the method, the logic is as follows:

  1. Generate a random long value using the provided rng instance.
  2. Shift the generated value one bit to the left and then one bit to the right, effectively clearing the sign bit.
  3. Calculate the remainder of dividing the resulting value by maxValue to bring it within the specified range.
  4. Repeat steps 1-3 until a valid value is obtained, satisfying the condition bits - val + (maxValue - 1) < 0L.
  5. Return the generated value.

This method provides a way to generate random long values within a given range using the provided random number generator.

sequence diagram

public static long bytesToLong(byte[] bytes)

public static long bytesToLong(byte[] bytes) {
    ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE);
    buffer.put(bytes);
    // need flip
    buffer.flip();
    return buffer.getLong();
}

The bytesToLong method is a static method defined in the io.nats.client.support.RandomUtils class. The method takes in a byte array as a parameter and converts it into a long value. Here is a step-by-step description of what the method does:

  1. Allocate a new ByteBuffer with the capacity equivalent to Long.SIZE. This means the buffer will have enough space to hold a long value.

  2. Copy the contents of the bytes parameter into the buffer using the put method. This will fill the buffer with the bytes from the byte array.

  3. Call the flip method on the buffer. This method is used to prepare the buffer for reading. It sets the buffer's limit to the current position and resets the position to 0.

  4. Retrieve the long value from the buffer using the getLong method. This method reads eight bytes from the buffer and interprets them as a long value.

  5. Return the long value.

In summary, the bytesToLong method takes a byte array, copies it into a ByteBuffer, flips the buffer to prepare it for reading, and then retrieves a long value from the buffer.

The bytesToLong method in the io.nats.client.support.RandomUtils class is a utility method that converts a byte array to a long value.

Here's how it works:

  1. The method takes a byte array (bytes) as input.
  2. It creates a ByteBuffer object with a size of Long.SIZE (which is the size of a long value in bits).
  3. The byte array is then copied into the ByteBuffer using the put method.
  4. The flip method is called on the ByteBuffer to prepare it for reading.
  5. Finally, the getLong method is called on the ByteBuffer to retrieve the long value.

In summary, the bytesToLong method allows you to convert a byte array to a long value using the ByteBuffer class.

sequence diagram

Digester

Digester

The Digester class is a utility class for making digesting data. It provides methods that can be used to compute digests of data using various algorithms.

public boolean matches(String digestEntry)

public boolean matches(String digestEntry) {
    String algo = digest.getAlgorithm().toUpperCase();
    if (!digestEntry.toUpperCase().startsWith(algo)) {
        return false;
    }
    // + 1 for equals
    return getDigestValue().equals(digestEntry.substring(algo.length() + 1));
}

Method Name: matches

This method is defined in the class io.nats.client.support.Digester and takes a String parameter named digestEntry. It returns a boolean value.

Parameters:

  • digestEntry: The digest entry that needs to be matched.

Description:

  • The method starts by converting the algorithm of the digest object (assuming it is an instance variable in the class) to uppercase using the toUpperCase() method.
  • It then checks if the digestEntry string starts with the uppercase algorithm string. If it doesn't, the method returns false.
  • If the digestEntry string does start with the algorithm string, the method compares the digest value obtained from the getDigestValue() method (assuming it is a method in the same class) with the substring of digestEntry obtained by removing the algorithm string plus one additional character (to remove the space after the algorithm).
  • If the digest value and the substring match, the method returns true. Otherwise, it returns false.

The matches method in the Digester class is used to check whether a given digestEntry string matches the expected algorithm and digest value.

The method first compares the starting characters of the digestEntry string with the uppercase value of the algorithm used to generate the digest. If they do not match, the method returns false.

If the starting characters match, the method then extracts the substring after the algorithm name and checks if it is equal to the expected digest value by calling the getDigestValue() method. If the extracted digest value matches the expected value, the method returns true, indicating a successful match.

Overall, this method provides a way to verify if a given digest entry matches the expected algorithm and digest value.

sequence diagram

IncomingHeadersProcessor

IncomingHeadersProcessor

The IncomingHeadersProcessor class is a public class that is responsible for processing incoming headers. It handles the processing of headers that are received by the software application.

private void initHeader(byte[] serialized, int len, Token tCrlf, boolean hadStatus)

private void initHeader(byte[] serialized, int len, Token tCrlf, boolean hadStatus) {
    // REGULAR HEADER
    Token peek = new Token(serialized, len, tCrlf, null);
    while (peek.isType(TokenType.TEXT)) {
        Token tKey = new Token(serialized, len, tCrlf, TokenType.KEY);
        Token tVal = new Token(serialized, len, tKey, null);
        if (tVal.isType(TokenType.SPACE)) {
            tVal = new Token(serialized, len, tVal, null);
        }
        if (tVal.isType(TokenType.TEXT)) {
            tCrlf = new Token(serialized, len, tVal, TokenType.CRLF);
        } else {
            tVal.mustBe(TokenType.CRLF);
            tCrlf = tVal;
        }
        if (headers == null) {
            headers = new Headers();
        }
        headers.add(tKey.getValue(), tVal.getValue());
        peek = new Token(serialized, len, tCrlf, null);
    }
    peek.mustBe(TokenType.CRLF);
}

The initHeader method in class io.nats.client.support.IncomingHeadersProcessor is responsible for initializing the headers based on the provided serialized byte array.

Here is a step-by-step description of what the method does:

  1. Initialize a Token object peek with the provided serialized byte array, length, and a token of type tCrlf.

  2. Start a while loop that iterates as long as the peek token is of type TEXT.

  3. Within the loop, create a new Token object tKey with the same parameters as peek, but with a token type of KEY.

  4. Create a new Token object tVal with the same parameters as tKey, but with a null token type.

  5. Check if tVal is of type SPACE. If it is, create a new Token object tVal using the current tVal as the base token and null as the token type.

  6. Check if tVal is of type TEXT. If it is, create a new Token object tCrlf using the current tVal as the base token and a token type of CRLF. Otherwise, tVal must be of type CRLF, so set tCrlf to tVal.

  7. Check if the headers object is null. If it is, initialize a new Headers object.

  8. Add the key-value pair represented by tKey and tVal to the headers object.

  9. Update the peek token to the next token in the array by creating a new Token object with the same parameters as tCrlf, but with a token type of null.

  10. Check that the peek token is of type CRLF. If it is not, an exception is thrown.

  11. Repeat the loop until the peek token is not of type TEXT.

Once the loop finishes, the method will have processed all the headers in the serialized byte array and stored them in the headers object.

The initHeader method is used to initialize the headers of a message. It takes in a serialized byte array, its length, a token representing the carriage return line feed (CRLF), and a boolean indicating whether the message had a status.

The method processes the serialized header information by iterating over the tokens. It starts by creating a peek token and checks if it is of type TEXT. If it is, it creates a tKey token representing the key of the header using the serialized byte array, its length, and the CRLF token.

Next, it creates a tVal token representing the value of the header. If the tVal token is of type SPACE, it creates a new token without a parent to eliminate the space.

Then, it checks if the tVal token is of type TEXT or CRLF. If it is TEXT, it sets the CRLF token to a new token with the tVal token as its parent. If it is CRLF, it sets the CRLF token to the tVal token itself.

If the headers object is null, it creates a new Headers object.

Finally, it adds the key-value pair to the headers object, and updates the peek token to continue processing the next token. This process continues until the peek token is of type CRLF.

The method ensures that the last token must be of type CRLF.

sequence diagram

private Token initStatus(byte[] serialized, int len, Token tSpace)

private Token initStatus(byte[] serialized, int len, Token tSpace) {
    Token tCode = new Token(serialized, len, tSpace, TokenType.WORD);
    Token tVal = new Token(serialized, len, tCode, null);
    Token crlf;
    if (tVal.isType(TokenType.SPACE)) {
        tVal = new Token(serialized, len, tVal, TokenType.TEXT);
        crlf = new Token(serialized, len, tVal, TokenType.CRLF);
    } else {
        tVal.mustBe(TokenType.CRLF);
        crlf = tVal;
    }
    inlineStatus = new Status(tCode, tVal);
    return crlf;
}

The initStatus method in the IncomingHeadersProcessor class is responsible for initializing the status of the incoming headers based on the provided byte[] serialized data.

Here is a step-by-step description of what the method does:

  1. The method takes in three parameters: serialized (the byte array containing the serialized data), len (the length of the serialized data), and tSpace (a token object of type Token).

  2. It creates a new token object tCode using the serialized, len, tSpace, and TokenType.WORD. The tCode token represents the code of the status.

  3. It creates a new token object tVal using the serialized, len, tCode, and null. Initially, tVal is set to null.

  4. It creates a new token object crlf to represent the carriage return line feed (CRLF) characters. The value of crlf will depend on the type of tVal.

  5. If tVal is of type TokenType.SPACE, it means that there is a space character between the status code and the status value. In this case, tVal is replaced with a new token object created using the serialized, len, tVal, and TokenType.TEXT. Then, crlf is set to a new token object created using the serialized, len, tVal, and TokenType.CRLF.

  6. If tVal is not of type TokenType.SPACE, it means that there is no space character between the status code and the status value. In this case, tVal must be of type TokenType.CRLF, and crlf is set to tVal.

  7. A new Status object is created using the tCode and tVal tokens, and assigned to the inlineStatus member variable.

  8. Finally, the method returns the crlf token.

This method essentially parses the serialized data, extracts the status code and value, creates a Status object, and returns the token representing the CRLF characters.

The initStatus method in the IncomingHeadersProcessor class takes in a byte array, its length, and a Token object as parameters. It initializes and sets the inlineStatus variable by creating a new Status object with tCode and tVal as its parameters. It then returns a Token object named crlf.

sequence diagram

NatsKeyValueUtil

NatsKeyValueUtil

The NatsKeyValueUtil class is an abstract class designed to provide utility methods for working with key-value stores in the Nats system. This class serves as a base for other classes that implement specific functionality for different types of key-value stores.

public static String trimPrefix(String bucketName)

public static String trimPrefix(String bucketName) {
    if (bucketName.startsWith(KV_STREAM_PREFIX)) {
        return bucketName.substring(KV_STREAM_PREFIX.length());
    }
    return bucketName;
}

Method Description - trimPrefix

The trimPrefix method is defined in the io.nats.client.support.NatsKeyValueUtil class and is used to remove a specific prefix string from the beginning of a given bucketName string.

Method Signature

public static String trimPrefix(String bucketName)

Parameters

  • bucketName - The string from which the prefix needs to be removed.

Return Value

  • String - The modified bucketName string after removing the prefix.

Steps

  1. Check if the bucketName starts with the prefix string KV_STREAM_PREFIX.
  2. If it starts with the prefix, then remove the prefix from the bucketName string by using the substring method with the index length of the KV_STREAM_PREFIX.
  3. Return the modified bucketName string without the prefix.
  4. If the bucketName does not start with the prefix, then simply return the bucketName as it is.

Code Snippet

public static String trimPrefix(String bucketName) {
    if (bucketName.startsWith(KV_STREAM_PREFIX)) {
        return bucketName.substring(KV_STREAM_PREFIX.length());
    }
    return bucketName;
}

The method trimPrefix in class NatsKeyValueUtil is a utility method that takes a String parameter bucketName and returns the bucketName with the prefix removed if it starts with the constant KV_STREAM_PREFIX.

If the bucketName starts with the KV_STREAM_PREFIX, the method returns the portion of the bucketName that comes after the KV_STREAM_PREFIX by using the substring method.

If the bucketName does not start with the KV_STREAM_PREFIX, the method simply returns the original bucketName.

sequence diagram

ByteArrayBuilder

ByteArrayBuilder

ByteArrayBuilder is a public class that extends BuilderBase. It is used to efficiently build byte arrays.

public int copyTo(byte[] dest, int destPos)

public int copyTo(byte[] dest, int destPos) {
    int len = length();
    byte[] hb = buffer.array();
    System.arraycopy(hb, 0, dest, destPos, len);
    return len;
}

The copyTo method in the io.nats.client.support.ByteArrayBuilder class is responsible for copying the contents of the internal buffer to a specified destination array.

Here is a step-by-step description of what the method does:

  1. Retrieve the length of the internal buffer using the length() method.

  2. Access the underlying byte array by calling buffer.array(), where buffer is an instance variable of type ByteBuffer.

  3. Use the System.arraycopy() method to copy the bytes from the internal buffer to the destination array. The source array is hb (the underlying byte array) and the starting position in the source array is 0. The destination array is dest, and the starting position in the destination array is destPos. The number of bytes to copy is len (the length of the internal buffer).

  4. Return the length of the copied data.

Please note that this description assumes that you have already imported the required classes and have instantiated an object of the ByteArrayBuilder class.

The copyTo method in the ByteArrayBuilder class, defined in the io.nats.client.support package, is used to copy the contents of the builder's internal buffer to a destination byte array.

The method takes two parameters: dest, which is the destination byte array where the contents will be copied to, and destPos, which is the starting position in the destination byte array where the copying will begin.

The method first retrieves the length of the data in the builder using the length method. Then, it accesses the internal buffer of the builder using the buffer.array() method and assigns it to the hb variable.

Finally, using the System.arraycopy() method, it copies the contents of the internal buffer (hb) to the specified destination byte array (dest) starting at the given position (destPos) and copied data length (len). The method then returns the length of the copied data.

In summary, the copyTo method allows you to efficiently copy the contents of the ByteArrayBuilder to a destination byte array, starting from a specified position.

sequence diagram

public ByteArrayBuilder ensureCapacity(int bytesNeeded)

public ByteArrayBuilder ensureCapacity(int bytesNeeded) {
    int bytesAvailable = buffer.capacity() - buffer.position();
    if (bytesAvailable < bytesNeeded) {
        ByteBuffer newBuffer = ByteBuffer.allocate(bufferAllocSize(buffer.position() + bytesNeeded, allocationSize));
        newBuffer.put(buffer.array(), 0, buffer.position());
        buffer = newBuffer;
    }
    return this;
}

The ensureCapacity method in the ByteArrayBuilder class defined in the io.nats.client.support package is used to ensure that the internal buffer has enough capacity to hold the specified number of bytes.

Here is a step-by-step description of what the method does:

  1. Get the number of bytes available in the buffer by subtracting the current position from the total capacity of the buffer.

  2. Check if the number of bytes available is less than the number of bytes needed.

  3. If the condition in step 2 is true, create a new ByteBuffer with a capacity calculated based on the current position of the buffer and the number of bytes needed.

  4. Copy the content of the existing buffer into the new buffer up to the current position.

  5. Set the internal buffer reference to the new buffer.

  6. Return a reference to the ByteArrayBuilder object to allow method chaining.

This method ensures that the ByteArrayBuilder has enough capacity to hold the specified number of bytes by creating a new buffer if necessary and copying the existing content into the new buffer.

The ensureCapacity method in the ByteArrayBuilder class is used to ensure that the buffer used by the ByteArrayBuilder has enough capacity to accommodate the specified number of bytes.

The method first calculates the number of bytes available in the current buffer by subtracting the buffer's position from its capacity. If the available capacity is less than the requested number of bytes, a new buffer is allocated with an increased size using the bufferAllocSize method.

The contents of the existing buffer are then copied into the new buffer, and the reference to the new buffer is assigned to the buffer field of the ByteArrayBuilder. Finally, the method returns a reference to the ByteArrayBuilder object itself.

In summary, the ensureCapacity method ensures that the ByteArrayBuilder has enough capacity to accommodate the requested number of bytes by reallocating a larger buffer if necessary.

sequence diagram

public ByteArrayBuilder append(CharBuffer src, Charset charset)

public ByteArrayBuilder append(CharBuffer src, Charset charset) {
    if (src == null) {
        append(NULL, 0, 4);
    } else {
        append(src.toString().getBytes(charset));
    }
    return this;
}

The append method in the ByteArrayBuilder class is used to add data to the builder's internal byte array.

Here is a step-by-step description of what the method does based on its body:

  1. It takes two parameters: src, which is a CharBuffer containing the data to be appended, and charset, which is the character set used for encoding the data.

  2. If the src parameter is null, it calls the append method of the ByteArrayBuilder class with the following parameters:

    • The NULL constant, which is a reference to a byte array representing the value null.
    • The offset (0), which specifies the starting index in the byte array.
    • The length (4), which indicates the number of bytes to be copied from the byte array.
  3. If the src parameter is not null, it converts the CharBuffer to a String by calling its toString method, and then gets the byte representation of the string using the specified charset encoding. This byte array is then passed to the overloaded append method of the ByteArrayBuilder class.

  4. After appending the data to the builder's internal byte array, the method returns a reference to the ByteArrayBuilder object itself, enabling method chaining.

Overall, the append method allows you to add data to the ByteArrayBuilder by providing a CharBuffer or a String object, and it takes care of converting the data to bytes using the specified character encoding.

The append method in the ByteArrayBuilder class of the io.nats.client.support package is used to add characters from a CharBuffer to the byte array.

First, it checks if the src (CharBuffer) is null. If it is, it appends NULL to the byte array. Otherwise, it converts the CharBuffer to a string using the specified charset and converts that string to bytes. Finally, it appends the resulting byte array to the existing byte array.

After performing these operations, the append method returns a reference to the current ByteArrayBuilder object, allowing for method chaining.

sequence diagram

public ByteArrayBuilder append(byte[] src)

public ByteArrayBuilder append(byte[] src) {
    if (src.length > 0) {
        ensureCapacity(src.length);
        buffer.put(src, 0, src.length);
    }
    return this;
}

The append method in the ByteArrayBuilder class is used to append a byte array to the existing builder object. Here is a step-by-step description of what the method does:

  1. Check if the length of the provided byte array (src) is greater than zero.
  2. If the length is greater than zero, proceed to the next step. Otherwise, return the current builder object.
  3. Call the ensureCapacity method to ensure that the internal buffer of the builder has enough space to accommodate the new bytes being appended.
  4. Use the put method to copy the bytes from the src array into the internal buffer of the builder, starting from index 0 and copying src.length number of bytes.
  5. Finally, return the updated builder object.

Note: The ensureCapacity method is not provided in the given code snippet. It is assumed to handle the resizing of the internal buffer to accommodate the new bytes if necessary.

The append method in the ByteArrayBuilder class (defined in io.nats.client.support) allows you to append a byte array to the existing byte array builder.

This method takes in a byte[] parameter named src. It first checks if the length of the src array is greater than zero. If it is, it ensures that the builder has enough capacity to accommodate the new byte array by calling the ensureCapacity method.

Finally, it uses the put method of the internal buffer to copy the content of the src array to the builder's buffer starting from index 0.

After appending the src array, the method returns a reference to the same ByteArrayBuilder object, allowing method chaining.

sequence diagram

public ByteArrayBuilder append(byte[] src, int len)

public ByteArrayBuilder append(byte[] src, int len) {
    if (len > 0) {
        ensureCapacity(len);
        buffer.put(src, 0, len);
    }
    return this;
}

The append method in the ByteArrayBuilder class of the io.nats.client.support package is used to append a byte array to the buffer managed by the ByteArrayBuilder object.

Here is a step-by-step description of what the append method does:

  1. Check if the given length len is greater than zero. If it is not, the method does nothing and returns the current ByteArrayBuilder object.

  2. If the length len is greater than zero, the method proceeds to the next step.

  3. Ensure that the buffer has enough capacity to accommodate the additional data. If the current capacity of the buffer is not sufficient, it will be increased to meet the required capacity.

  4. Copy the first len bytes from the source byte array src into the buffer managed by the ByteArrayBuilder object. The put method of the buffer is used for this purpose.

  5. The method returns the current ByteArrayBuilder object, which allows for method chaining.

In summary, the append method appends a specified number of bytes from a given byte array to the buffer managed by the ByteArrayBuilder object, ensuring that the buffer has enough capacity to hold the data.

The append method defined in the ByteArrayBuilder class in the io.nats.client.support package is used to append bytes from a source byte array into the ByteArrayBuilder object. The method takes two parameters: src, which is the source byte array, and len, which specifies the number of bytes to append from the source array.

The method first checks if the len value is greater than 0, indicating that there are bytes to be appended. If len is greater than 0, the method ensures that the ByteArrayBuilder has enough capacity to accommodate the additional bytes.

Finally, the method uses the put method of the internal buffer object to append the specified number of bytes from the source array into the ByteArrayBuilder.

The method returns the updated ByteArrayBuilder object, allowing for chained method calls if needed.

sequence diagram

public ByteArrayBuilder append(byte[] src, int offset, int len)

public ByteArrayBuilder append(byte[] src, int offset, int len) {
    if (len > 0) {
        ensureCapacity(len);
        buffer.put(src, offset, len);
    }
    return this;
}

The append method in the io.nats.client.support.ByteArrayBuilder class is used to add a specified portion of a byte array to the current buffer.

Here is a step by step description of what the method does:

  1. Check if the specified length (len) is greater than 0.
  2. If the length is greater than 0, proceed to the next step.
  3. Call the ensureCapacity method to make sure that the buffer has enough capacity to accommodate the specified length.
  4. Use the put method of the buffer to copy the specified portion of the source byte array (src) into the buffer. The offset and length of the portion to be copied are specified by the offset and len parameters.
  5. Return a reference to the current instance of the ByteArrayBuilder to allow for method chaining.

Overall, the append method appends a portion of a byte array to the buffer and returns a reference to the ByteArrayBuilder.

The append method, defined in the ByteArrayBuilder class of the io.nats.client.support package, is used to append a specified portion of a byte array to the existing byte array held by the builder.

The method takes three arguments: src (the source byte array from which the portion needs to be appended), offset (the starting index in the source array from where the portion begins), and len (the length of the portion to be appended).

First, the method checks if the length of the portion to be appended is greater than zero. If it is, the method proceeds to ensure that the builder's internal buffer has enough capacity to accommodate the new portion. If necessary, the buffer's size is increased.

Finally, the portion of the source byte array specified by the offset and len arguments is copied into the builder's buffer using the put method. The builder's reference is then returned.

In summary, the append method is responsible for appending a specified portion of a byte array to the byte array held by the builder, ensuring capacity if needed.

sequence diagram

public ByteArrayBuilder append(ByteArrayBuilder bab)

public ByteArrayBuilder append(ByteArrayBuilder bab) {
    if (bab != null && bab.length() > 0) {
        append(bab.buffer.array(), 0, bab.length());
    }
    return this;
}

The append method in the ByteArrayBuilder class is used to concatenate the contents of another ByteArrayBuilder object to the current object.

Here are the steps performed by this method:

  1. Check if the provided ByteArrayBuilder object, bab, is not null and has a length greater than 0.
  2. If bab is not null and has a length greater than 0: a. Retrieve the buffer array from bab using bab.buffer.array(). b. Call the append method of the current ByteArrayBuilder object, passing the buffer array, a starting index of 0, and the length of bab as parameters.
  3. Return the current ByteArrayBuilder object.

In summary, this append method adds the contents of another ByteArrayBuilder object to the current object, as long as the provided ByteArrayBuilder is not null and has a non-zero length.

The append method in the ByteArrayBuilder class in the io.nats.client.support package is used to append the contents of another ByteArrayBuilder object to the current ByteArrayBuilder object.

In the method, it first checks if the bab object is not null and if it has a length greater than zero. If these conditions are met, it calls the append method again with the byte array, start index, and length of the bab object. This effectively appends the contents of bab to the current ByteArrayBuilder.

Finally, it returns the current ByteArrayBuilder object, allowing for method chaining if desired.

sequence diagram

NatsObjectStoreUtil

NatsObjectStoreUtil

NatsObjectStoreUtil is an abstract class representing a utility for interacting with an object store in the context of a Nats system. This class provides methods for managing and manipulating objects within the store, allowing software engineers to efficiently store and retrieve data.

WebsocketInputStream

WebsocketInputStream

The WebsocketInputStream class is a Java class that extends the InputStream class. It provides a specialized input stream for handling WebSocket connections. With this class, you can read data from a WebSocket connection as if it were a regular input stream.

@Override

public int read(byte[] buffer, int offset, int length) throws IOException

@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
    // Just in case we get headers with empty payloads:
    while (0 == header.getPayloadLength()) {
        if (!readHeader()) {
            return -1;
        }
    }
    if (header.getOpCode() == OpCode.CLOSE) {
        // Ignore the websocket close message body:
        in.skip(header.getPayloadLength());
        return -1;
    }
    final long headerPayloadLength = header.getPayloadLength();
    final int payloadLength = Math.min(length, headerPayloadLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) headerPayloadLength);
    length = in.read(buffer, offset, payloadLength);
    if (-1 == length) {
        return length;
    }
    return header.filterPayload(buffer, offset, length);
}

The read method in the io.nats.client.support.WebsocketInputStream class is used to read data from a WebSocket connection. Here is a step-by-step description of what this method does based on its body:

  1. Check if the payload length in the header is zero. This is done in a while loop to handle the case where headers with empty payloads are received. If the payload length is zero, it means there is no data to read and the next header is fetched.

  2. If the operation code in the header is CLOSE, it means it is a WebSocket close message. In this case, the method skips the length specified in the header, ignoring the close message body, and returns -1 to indicate the end of the stream.

  3. Get the payload length from the header and determine the length of the data to be read. This length is the minimum of the specified length parameter and the payload length, considering the maximum value of an integer.

  4. Invoke the read method of the underlying input stream (in) to read the data into the given buffer, starting at the specified offset, and up to the determined payload length. The actual number of bytes read is stored in the length variable.

  5. Check if the end of the stream has been reached. If the value returned by the read method is -1, it means no more data can be read and the method returns -1.

  6. Filter the payload using the filterPayload method in the header. This method applies any filtering or transformations to the payload before returning it.

  7. Finally, the method returns the filtered payload length.

This read method handles the reading of WebSocket data, excluding the header and any close message, and applies any necessary payload filtering before returning the data.

The read method in the WebsocketInputStream class is responsible for reading data from the input stream of a WebSocket connection.

Here are the steps performed by the method:

  1. It checks if the headers have empty payloads. If so, it continues reading the headers until a non-empty payload is found.
  2. If the OpCode of the header is CLOSE, it skips the WebSocket close message body and returns -1 to indicate the end of the stream.
  3. It determines the payload length based on the smaller of the provided length or the header's payload length. If the header's payload length is greater than Integer.MAX_VALUE, it sets the payload length to Integer.MAX_VALUE.
  4. It reads data from the underlying input stream in into the provided buffer starting from the specified offset and up to the determined payload length.
  5. If the read length is -1, it indicates the end of the stream and returns -1.
  6. Finally, it applies a filter to the payload in the buffer, starting from the specified offset and with the read length, using the header.filterPayload method. The filtered payload is returned as the result of the read method.

sequence diagram

@Override

public int read() throws IOException

@Override
public int read() throws IOException {
    int result = read(oneByte, 0, 1);
    if (-1 == result) {
        return result;
    }
    return oneByte[0];
}

The read() method in the WebsocketInputStream class, located in the io.nats.client.support package, is used to read bytes from the websocket input stream.

Here is a step-by-step description of what the method is doing:

  1. The method overrides the read() method from the InputStream class and indicates that it can throw an IOException.

  2. In the method, a variable named result is declared to hold the result of the next step.

  3. The read() method is called on the WebsocketInputStream object, passing in the oneByte array, starting at index 0, and specifying the number of bytes to read as 1. This method call reads one byte from the websocket input stream and stores it in the oneByte array.

  4. The result variable is assigned the value returned by the read() method. If the value is equal to -1, it signifies the end of the stream has been reached, so the result is returned.

  5. If the result is not equal to -1, the method returns the first element of the oneByte array, which represents the byte that was read.

In summary, the read() method reads one byte from the websocket input stream, stores it in the oneByte array, and returns that byte. If the end of the stream is reached, it returns -1.

This method, read, is an override of the read method defined in the WebsocketInputStream class in the io.nats.client.support package.

The purpose of this method is to read a single byte from the input stream and return it as an integer. It does this by calling the read method with a byte array of size 1, and then returning the first element of that array as an integer. If the result of the read operation is -1 (indicating the end of the input stream), then -1 is returned.

sequence diagram

private boolean readHeader() throws IOException

private boolean readHeader() throws IOException {
    int len = 0;
    while (len < 2) {
        int result = in.read(buffer, len, 2 - len);
        if (result < 0) {
            return false;
        }
        len += result;
    }
    int headerSize = WebsocketFrameHeader.size(buffer, 0);
    if (headerSize > 2) {
        while (len < headerSize) {
            int result = in.read(buffer, len, headerSize - len);
            if (result < 0) {
                return false;
            }
            len += result;
        }
    }
    header.write(buffer, 0, headerSize);
    return true;
}

The readHeader method is defined in the WebsocketInputStream class and is responsible for reading the header of a WebSocket frame. Here is a step-by-step description of its functionality:

  1. Create a variable len and set it to 0.
  2. Start a while loop and continue until len is less than 2.
  3. Read from the input stream (in) and store the result in a variable result using the read method of the input stream. The buffer is used as the destination for the read bytes. The number of bytes to read is 2 - len, which ensures that two bytes are read in total.
  4. Check if result is less than 0. If true, it means that the end of the stream has been reached, so return false.
  5. Increment len by the value of result to keep track of the number of bytes read so far.
  6. If the code execution reaches this point, it means that len is at least 2.
  7. Calculate the size of the header by calling the size method of the WebsocketFrameHeader class, passing in the buffer and 0 as parameters. Store the result in a variable headerSize.
  8. Check if headerSize is greater than 2. If true, it means that the header contains metadata beyond the initial two bytes.
  9. Start a while loop and continue until len is less than headerSize.
  10. Read from the input stream (in) and store the result in a variable result using the read method of the input stream. The number of bytes to read is headerSize - len, which ensures that the remaining bytes of the header are read.
  11. Check if result is less than 0. If true, it means that the end of the stream has been reached, so return false.
  12. Increment len by the value of result to keep track of the number of bytes read so far.
  13. If the code execution reaches this point, it means that all the bytes of the header have been read.
  14. Write the header bytes to the header object using the write method, passing in the buffer, 0, and headerSize as parameters.
  15. Return true to indicate that the header has been successfully read.

The readHeader method in the io.nats.client.support.WebsocketInputStream class is responsible for reading the header of a WebSocket frame from an input stream.

The method initially reads 2 bytes from the input stream and stores them in a buffer. If the result is less than 0 (signifying the end of the input stream), the method returns false. Otherwise, it keeps reading from the input stream until it has read 2 bytes.

The method then calculates the header size using the WebsocketFrameHeader.size method, passing the buffer and the offset 0. If the header size is greater than 2, the method continues reading from the input stream until it has read headerSize bytes.

Finally, the method writes the header bytes from the buffer to the header object and returns true.

Overall, the readHeader method is responsible for reading and processing the header of a WebSocket frame from an input stream.

sequence diagram

Token

Token

The Token class represents a token, which is an essential element for parsing and processing data. This class provides a structure to store and manage tokens, allowing engineers to easily manipulate and analyze data using tokens.

JsonParser

JsonParser

The JsonParser class is a public class that provides functionality for parsing JSON data. It allows developers to easily convert JSON strings or files into Java objects, making it easier to work with JSON data in a structured and organized manner. The class offers various methods for parsing JSON, including parsing from a string, parsing from a file, and parsing directly from an input stream. Additionally, it supports parsing of JSON arrays, objects, and individual values, supporting a wide range of JSON data structures.

public static JsonValue parseUnchecked(char[] json)

public static JsonValue parseUnchecked(char[] json) {
    try {
        return parse(json);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

Method Description: parseUnchecked in class io.nats.client.support.JsonParser

This method is a public static method that takes a single parameter json of type char[] and returns a JsonValue.

Steps:

  1. The method starts by wrapping the core parsing logic in a try-catch block.

  2. Inside the try block, the parse(json) method is called to parse the given JSON string.

  3. If the JSON parsing is successful, the parsed JsonValue object is returned.

  4. If an exception of type JsonParseException is caught during the parsing process, it is wrapped in a RuntimeException and rethrown.

  5. Upon catching the JsonParseException, a new instance of RuntimeException is created with the caught exception as the cause.

  6. The RuntimeException is then thrown, propagating the original exception as an unchecked exception.

Note: This method provides a convenient way to parse JSON strings without explicitly handling the checked JsonParseException, allowing for cleaner code at the calling code level. However, it also introduces a risk of catching other types of exceptions and throwing them as unchecked exceptions. Hence, caution should be exercised while using this method.

The parseUnchecked method in the JsonParser class is a static method that takes a char array containing JSON data as input and returns a JsonValue object.

Internally, the method calls another method parse to parse the JSON data. If there is a JsonParseException during the parsing process, the method catches it and throws a RuntimeException with the same exception as the cause.

This method is useful when you want to parse JSON data without explicitly handling the exception. However, be aware that this method may throw a RuntimeException if the parsing fails.

sequence diagram

public static JsonValue parseUnchecked(char[] json, int startIndex)

public static JsonValue parseUnchecked(char[] json, int startIndex) {
    try {
        return parse(json, startIndex);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

Method Name: parseUnchecked

Description:

This method is used to parse a JSON string into a Java JsonValue object. It takes a character array representing the JSON string and the starting index as parameters. If the JSON parsing fails and throws a JsonParseException, it catches the exception and rethrows a RuntimeException.

Method Signature:

public static JsonValue parseUnchecked(char[] json, int startIndex)

Parameters:

  • json : a character array representing the JSON string to be parsed.
  • startIndex : the starting index in the json array from where parsing should begin.

Return Type:

JsonValue : a Java object representing the parsed JSON value.

Steps:

  1. Invoke the parse method with the json and startIndex parameters.
  2. If the parsing is successful, return the parsed JsonValue.
  3. If a JsonParseException is thrown during the parsing process: a. Catch the exception. b. Throw a RuntimeException with the caught JsonParseException as its cause.

The parseUnchecked method, defined in the JsonParser class in the io.nats.client.support package, is responsible for parsing a JSON string into a JsonValue object without explicitly handling any exceptions.

The method takes a char array json and an int startIndex as parameters. It internally calls the parse method from the same class, passing the json and startIndex values. If the parse method throws a JsonParseException, it catches the exception and rethrows it as a RuntimeException.

In other words, the parseUnchecked method provides a simplified way to parse a JSON string without having to handle the JsonParseException explicitly. However, it does come with the risk of an unchecked exception being thrown if the given JSON string is invalid.

sequence diagram

public static JsonValue parseUnchecked(char[] json, Option... options)

public static JsonValue parseUnchecked(char[] json, Option... options) {
    try {
        return parse(json, options);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

The parseUnchecked method in the io.nats.client.support.JsonParser class is responsible for parsing a JSON string and returning a JsonValue object. Below is a step-by-step description of what this method does:

  1. The parseUnchecked method accepts two parameters: json, a character array containing the JSON string to be parsed, and options, an optional array of Option objects.
  2. The method tries to parse the JSON string using the parse method, passing in the json and options parameters.
  3. If the parse is successful, the method returns the resulting JsonValue object.
  4. If an exception of type JsonParseException is thrown during the parse, the method catches it and rethrows it as a RuntimeException. This is done to simplify error handling, as the parse method may throw a checked exception.
  5. If the exception is rethrown as a RuntimeException, the caller of the parseUnchecked method will need to handle it appropriately.

Overall, the parseUnchecked method provides a simplified way to parse a JSON string without having to handle checked exceptions directly.

The parseUnchecked method is a static method defined in the JsonParser class within the io.nats.client.support package.

This method takes a char array json as input, along with optional Option arguments. The purpose of this method is to parse the given JSON string and return a JsonValue object.

Internally, the method calls the parse method from the same class which returns a JsonValue object. If a JsonParseException occurs during the parsing process, it is caught and re-thrown as a RuntimeException.

Overall, the parseUnchecked method allows for easy and unchecked parsing of a JSON string into a JsonValue object, simplifying exception handling for the caller.

sequence diagram

public static JsonValue parseUnchecked(char[] json, int startIndex, Option... options)

public static JsonValue parseUnchecked(char[] json, int startIndex, Option... options) {
    try {
        return parse(json, startIndex, options);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

Method: parseUnchecked

The parseUnchecked method is defined in the io.nats.client.support.JsonParser class.

Description

The parseUnchecked method is used to parse a JSON value from a character array, starting from a specified index. This method internally calls the parse method and handles any JsonParseException by throwing a RuntimeException.

Syntax

public static JsonValue parseUnchecked(char[] json, int startIndex, Option... options)

Parameters

The method takes the following parameters:

  1. json - A character array containing the JSON string to parse.
  2. startIndex - An integer representing the index in the json array from where the parsing should start.
  3. options (optional) - One or more Option objects specifying parsing options.

Return Value

The method returns a JsonValue representing the parsed JSON value.

Exceptions

The method may throw a RuntimeException if a JsonParseException occurs during parsing.

Example Usage

char[] json = "{\"name\": \"John\", \"age\": 30}".toCharArray();
int startIndex = 0;

try {
    JsonValue result = JsonParser.parseUnchecked(json, startIndex);
    System.out.println(result);
} catch (RuntimeException e) {
    System.err.println("Failed to parse JSON: " + e.getMessage());
}

In the above example, the parseUnchecked method is called with a JSON string and a starting index of 0. The parsed JsonValue is then printed to the console. If a JsonParseException occurs, a RuntimeException is thrown and the error message is printed to the console.

The parseUnchecked method in the JsonParser class is a public static method that allows you to parse a JSON string into a JsonValue object.

This method takes in three parameters:

  • json: a character array representing the JSON string to be parsed
  • startIndex: an integer representing the starting index of the JSON string
  • options: an optional array of Option objects that can be used to customize the parsing behavior

Internally, the parseUnchecked method calls the parse method from the same class, passing in the provided parameters and options. If an exception of type JsonParseException is caught during the parsing process, it is wrapped in a RuntimeException and re-thrown.

Overall, the purpose of this method is to provide a convenient way to parse a JSON string into a JsonValue object, while handling any parsing exceptions in a consistent manner.

sequence diagram

public static JsonValue parseUnchecked(String json)

public static JsonValue parseUnchecked(String json) {
    try {
        return parse(json);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

Method: parseUnchecked(String json)

The parseUnchecked method in the JsonParser class is used to parse JSON data provided as a string and return a corresponding JsonValue object.

Steps:

  1. The method accepts a json parameter, which is a string containing the JSON data to be parsed.
  2. Inside the method, a try-catch block is used to handle any potential JsonParseException that may occur during parsing.
  3. The parse method is called with the json parameter to parse the JSON data and return a JsonValue object.
  4. If no exception occurs during parsing, the parsed JsonValue object is returned.
  5. If a JsonParseException occurs, it is caught in the catch block.
  6. Inside the catch block, a RuntimeException is thrown with the caught JsonParseException as the cause.
  7. This allows any exception during parsing to be re-thrown as a RuntimeException.
  8. Finally, the parseUnchecked method is concluded.

Note: It's important to handle exceptions during parsing JSON data as parsing errors can occur if the JSON structure is not properly formatted.

Method Description

The parseUnchecked method in the JsonParser class is a static method that takes a JSON string as input and returns a JsonValue object.

This method calls the parse method, which is responsible for parsing the JSON string and returning the corresponding JsonValue object. However, if a JsonParseException occurs during the parsing process, the method catches the exception and rethrows it as a RuntimeException to ensure the caller is aware of the failure.

The parseUnchecked method is designed to provide a convenient way to parse a JSON string without explicitly handling the JsonParseException. This is useful in scenarios where the caller expects the input JSON to be valid and does not want to handle the exception explicitly.

public static JsonValue parseUnchecked(String json, int startIndex)

public static JsonValue parseUnchecked(String json, int startIndex) {
    try {
        return parse(json, startIndex);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

parseUnchecked Method Description

The parseUnchecked method in class io.nats.client.support.JsonParser is used to parse a JSON string starting from a specified index. It takes two parameters, a String representing the JSON string to be parsed, and an int representing the index at which parsing should begin.

  1. The method starts by wrapping the parsing logic in a try-catch block. This is done to catch any JsonParseException that may occur while parsing the JSON string.

  2. Inside the try block, the parse method is called, passing the json string and startIndex as arguments. The parse method is responsible for parsing the JSON string and returning the parsed result as a JsonValue object.

  3. If the parsing is successful, the parsed JsonValue object is returned from the parseUnchecked method.

  4. However, if a JsonParseException is caught during parsing, the method throws a RuntimeException. This is done by wrapping the caught exception in a RuntimeException and rethrowing it. This allows the calling code to handle the exception in a consistent manner.

In summary, the parseUnchecked method provides a convenient way to parse a JSON string starting from a specified index. It handles any JsonParseException that may occur during parsing and rethrows it as a RuntimeException for consistent error handling.

The parseUnchecked method is a static method defined in the JsonParser class of the io.nats.client.support package.

This method takes a JSON string and a starting index as parameters and returns a JsonValue object representing the parsed JSON value. It uses the parse method (which is not explicitly defined in the code snippet) to parse the JSON string, starting from the specified index. If a JsonParseException occurs during the parsing process, it is caught and re-thrown as a RuntimeException.

Based on the code provided, this method provides a way to parse a JSON string and obtain a JsonValue object representation, ensuring that any exceptions thrown during parsing are handled and converted to a RuntimeException.

sequence diagram

public static JsonValue parseUnchecked(String json, Option... options)

public static JsonValue parseUnchecked(String json, Option... options) {
    try {
        return parse(json, options);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

The method parseUnchecked in the class io.nats.client.support.JsonParser is responsible for parsing a JSON string and returning a JsonValue object. Here is a step-by-step description of what the method does:

  1. The method accepts a JSON string as the json parameter and an optional array of Option objects as the options parameter.
  2. Inside the method, it tries to parse the json string by calling the parse method (which is not included in the provided code snippet), passing the json and options parameters.
  3. If the parse method throws a JsonParseException, it catches the exception and throws a new RuntimeException wrapping the original exception.
  4. If the parse method successfully parses the JSON string, it returns a JsonValue object.

It's worth noting that the actual implementation of the parse method is not shown in the provided code snippet, so the specific parsing logic is unknown. However, based on the provided code, we can infer that the parse method is expected to handle the parsing of the json string and return a JsonValue object accordingly.

The parseUnchecked method in the JsonParser class is a static method that accepts a JSON string as input and optional parsing options. It uses the parse method from the same class to parse the provided JSON string. If a JsonParseException occurs during the parsing process, it catches the exception and rethrows it as a RuntimeException.

In summary, the parseUnchecked method parses a JSON string and handles any parsing exceptions by throwing a RuntimeException.

sequence diagram

public static JsonValue parseUnchecked(String json, int startIndex, Option... options)

public static JsonValue parseUnchecked(String json, int startIndex, Option... options) {
    try {
        return parse(json, startIndex, options);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

Method: parseUnchecked

public static JsonValue parseUnchecked(String json, int startIndex, Option... options) {
    try {
        return parse(json, startIndex, options);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

This method is defined in the JsonParser class in the io.nats.client.support package.

Parameters

  • json (String): The JSON string to parse.
  • startIndex (int): The index to start parsing from.
  • options (Option...): Optional parsing options.

Return Value

  • JsonValue: The parsed JSON value.

Description

This method is used to parse a JSON string into a JsonValue object.

  1. The method starts by calling the parse method, passing the json, startIndex, and options parameters.
  2. If the parse method throws a JsonParseException, it catches the exception and throws a RuntimeException with the original exception as the cause.
  3. If the parse method is successful, it returns the parsed JSON value.

Note: The JsonParseException is a checked exception. This method wraps it in a RuntimeException to allow it to be used without explicitly handling the exception.

The parseUnchecked method is a static method defined in the io.nats.client.support.JsonParser class. It takes three parameters: json (a string representing JSON), startIndex (an integer specifying the index from which to start parsing), and options (an array of Option objects specifying parsing options).

The purpose of this method is to parse a JSON string into a JsonValue object. It uses the parse method from the same class, passing the provided parameters. If an exception of type JsonParseException is thrown during the parsing process, it catches the exception and rethrows it as a RuntimeException.

Overall, this method provides a convenient way to parse a JSON string without explicitly handling the JsonParseException exception, making it suitable for situations where exception handling can be simplified.

sequence diagram

public static JsonValue parseUnchecked(byte[] json)

public static JsonValue parseUnchecked(byte[] json) {
    try {
        return parse(json);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

Method: parseUnchecked

This method is defined in the class io.nats.client.support.JsonParser. It takes a single parameter, json, which represents a byte array of JSON data.

The purpose of this method is to parse the given JSON data and return the resulting JsonValue.

The method executes the following steps:

  1. It tries to invoke the parse method by passing the json parameter.
  2. If the parse method throws a JsonParseException, the method catches it and throws a new RuntimeException. This is done to convert the checked exception into an unchecked exception.

Please note that the parse method is not defined in the provided body. It is assumed to be present in the io.nats.client.support.JsonParser class and handles the actual parsing of the JSON data.

The parseUnchecked method in the JsonParser class is a utility method for parsing JSON data represented as a byte array into a JsonValue object.

The method calls the parse method, which is responsible for performing the actual parsing of the JSON data. If a JsonParseException is thrown during the parsing process, it is caught and rethrown as a RuntimeException.

This method is named "parseUnchecked" because it wraps the checked exception (JsonParseException) into an unchecked exception (RuntimeException), allowing a caller to handle any parsing errors in a more consistent and simplified manner.

sequence diagram

public static JsonValue parseUnchecked(byte[] json, Option... options)

public static JsonValue parseUnchecked(byte[] json, Option... options) {
    try {
        return parse(json, options);
    } catch (JsonParseException j) {
        throw new RuntimeException(j);
    }
}

The parseUnchecked method is defined in the JsonParser class of the io.nats.client.support package. It takes a byte array as input and an optional array of Option objects.

The purpose of this method is to parse the given byte array as JSON and return the parsed JsonValue object. However, since the parse method that actually performs the parsing can throw a JsonParseException, the parseUnchecked method catches this exception and rethrows it as a RuntimeException.

Here is a step-by-step description of what the parseUnchecked method does:

  1. The method signature declares the method as public static, meaning it can be called without an instance of the JsonParser class and it can be called from any other class in the same package or from a different package.

  2. The method takes two parameters: byte[] json, which represents the JSON data to be parsed, and Option... options, which is an optional array of Option objects that can be used to customize the parsing behavior.

  3. Inside the method, a try-catch block is used to handle any JsonParseException that might occur during the parsing process.

  4. The try block calls the parse method, passing the json byte array and the options array as arguments, to perform the actual parsing and return the resulting JsonValue object.

  5. If the parsing is successful and no JsonParseException is thrown, the parsed JsonValue object is returned by the parse method.

  6. If a JsonParseException is thrown during the parsing process, the catch block catches it, encapsulates it inside a RuntimeException, and throws this new exception.

  7. The RuntimeException that is thrown in case of a parsing error will contain the original JsonParseException as its cause.

Overall, the parseUnchecked method provides a convenient way to parse JSON data without explicitly handling the JsonParseException, as it wraps any thrown exception and rethrows it as a RuntimeException.

The parseUnchecked method in the JsonParser class is a static method that takes a byte array json as input along with optional Option parameters.

This method is used to parse the given byte array json into a JsonValue object. It internally calls the parse method with the given parameters and returns the parsed JsonValue.

If the parsing fails and throws a JsonParseException, the method catches the exception and rethrows it as a RuntimeException. This is done to handle any parsing errors in a more generic way.

Overall, this method allows for parsing a byte array of JSON data into a JsonValue object, with the option to customize the parsing behavior using optional parameters.

sequence diagram

public JsonValue parse() throws JsonParseException

public JsonValue parse() throws JsonParseException {
    char c = peekToken();
    if (c == 0) {
        return NULL;
    }
    return nextValue();
}

JsonParser.parse() Method

The parse() method is defined in the JsonParser class, located in the io.nats.client.support package. It is used to parse a JSON string and return the corresponding JsonValue object. The method has the following steps:

  1. Get the next character from the JSON string by calling the peekToken() method and assign it to the variable c.
  2. Check if the character c is equal to 0 (null character). If it is, return a NULL JsonValue object.
  3. If the character c is not null, call the nextValue() method to parse the next JSON value and return it.

The method may throw a JsonParseException if there are any issues encountered during the parsing process.

The parse method in the JsonParser class is used to parse a JSON string and convert it into a JsonValue object.

It starts by checking the next token in the JSON string using the peekToken method. If the next token is a null character (ASCII value 0), it returns a NULL value indicating that the JSON string is empty.

Otherwise, it calls the nextValue method to parse the next JSON value in the string and returns it. The nextValue method is responsible for iterating through the JSON string and parsing each individual value.

If any error occurs while parsing the JSON string, a JsonParseException is thrown.

In summary, the parse method takes a JSON string as input, checks if it is empty, and if not, parses it into a JsonValue object.

sequence diagram

private JsonValue nextValue() throws JsonParseException

private JsonValue nextValue() throws JsonParseException {
    char c = peekToken();
    if (c == 0) {
        throw new JsonParseException("Unexpected end of data.");
    }
    if (c == '"') {
        nextToken();
        return new JsonValue(nextString());
    }
    if (c == '{') {
        nextToken();
        return new JsonValue(nextObject());
    }
    if (c == '[') {
        nextToken();
        return new JsonValue(nextArray());
    }
    return nextPrimitiveValue();
}

The nextValue method is defined in the JsonParser class within the io.nats.client.support package. This method is responsible for parsing the next JSON value in a string and returning it as a JsonValue object. Here is a step-by-step description of what this method does:

  1. Get the next character from the input string using the peekToken method and assign it to the variable c.
  2. Check if the value of c is 0, which indicates the end of the input data. If it is, throw a JsonParseException with the message "Unexpected end of data."
  3. Check if the value of c is ". If it is, call the nextToken method to consume the ", then call the nextString method to parse the next JSON string, and finally return a new JsonValue object with the parsed string.
  4. Check if the value of c is {. If it is, call the nextToken method to consume the {, then call the nextObject method to parse the next JSON object, and finally return a new JsonValue object with the parsed object.
  5. Check if the value of c is [. If it is, call the nextToken method to consume the [, then call the nextArray method to parse the next JSON array, and finally return a new JsonValue object with the parsed array.
  6. If none of the above conditions are met, call the nextPrimitiveValue method to parse the next JSON primitive value, and return the result.

Overall, the nextValue method determines the type of the next JSON value (string, object, array, or primitive) based on the next character in the input string and uses the appropriate method to parse and return the value as a JsonValue object.

The nextValue method is a private method defined in the JsonParser class in the io.nats.client.support package. This method is used to parse the next JSON value from the input data.

The method starts by checking the next character in the input data and throws a JsonParseException if it encounters an unexpected end of data.

Next, it checks if the next character is a double quotation mark ("), indicating that the next value is a string. If it is, it moves to the next character and returns a new JsonValue object containing the parsed string.

If the next character is an opening curly brace ({), indicating the start of an object, it moves to the next character and returns a new JsonValue object containing the parsed object.

Similarly, if the next character is an opening square bracket ([), indicating the start of an array, it moves to the next character and returns a new JsonValue object containing the parsed array.

If none of the above conditions are met, it assumes the next value is a primitive value (e.g., number, boolean, or null) and calls the nextPrimitiveValue method to parse it. The result is then returned as a JsonValue object.

In summary, the nextValue method in the JsonParser class is responsible for parsing the next JSON value from the input data, handling different types of values such as strings, objects, arrays, and primitive values.

sequence diagram

private List nextArray() throws JsonParseException

private List<JsonValue> nextArray() throws JsonParseException {
    List<JsonValue> list = new ArrayList<>();
    char p = peekToken();
    while (p != ']') {
        if (p == ',') {
            // advance past the peek
            nextToken();
        } else {
            list.add(nextValue());
        }
        p = peekToken();
    }
    // advance past the peek
    nextToken();
    return list;
}

The nextArray() method is a private method defined in the io.nats.client.support.JsonParser class. It is responsible for parsing a JSON array and returning a List of JsonValue objects.

Here is a step-by-step description of how the nextArray() method works:

  1. Create a new ArrayList called list to store the JsonValue objects.
  2. Peek at the next token using the peekToken() method and store it in a variable called p.
  3. Start a loop that continues until the next token is ']'.
  4. Inside the loop, check if the next token is ','. If it is, advance past the token by calling the nextToken() method.
  5. If the next token is not ',', it means it is a JSON value. Call the nextValue() method to parse the value and add it to the list using the add() method.
  6. Peek at the next token again and update the value of p.
  7. After the loop, call the nextToken() method to advance past the closing '[' token.
  8. Return the list containing the parsed JSON values.

It is worth noting that the nextArray() method assumes that the input JSON is well-formed, with elements separated by commas and enclosed in square brackets. If the JSON is not well-formed, the method may throw a JsonParseException.

The nextArray method in the JsonParser class is used to parse and retrieve a list of JsonValue objects from a JSON string.

Here's a brief overview of what the method does:

  1. It initializes an empty ArrayList to store the parsed JsonValue objects.
  2. It checks the next character in the JSON string (referred to as p) to determine if the end of the array is reached.
  3. If p is not ']', it proceeds to check if p is ',' or a value by calling other methods.
  4. If p is ',', it advances to the next token and checks the new p again.
  5. If p is neither ']' nor ',', it calls the nextValue method to parse and retrieve the next JsonValue object, and adds it to the list.
  6. After adding the value to the list, it proceeds to check the new p again.
  7. This process continues until p is ']'.
  8. Once the end of the array is reached, it advances to the next token (i.e., the next character after ']') for further parsing.
  9. Finally, it returns the list of parsed JsonValue objects.

In summary, the nextArray method reads and processes the JSON array tokens, extracting the JsonValue objects and returning a list of those objects.

sequence diagram

private JsonValue nextPrimitiveValue() throws JsonParseException

private JsonValue nextPrimitiveValue() throws JsonParseException {
    StringBuilder sb = new StringBuilder();
    char c = peekToken();
    while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
        sb.append(nextToken());
        c = peekToken();
    }
    String string = sb.toString();
    if ("true".equalsIgnoreCase(string)) {
        return new JsonValue(Boolean.TRUE);
    }
    if ("false".equalsIgnoreCase(string)) {
        return new JsonValue(Boolean.FALSE);
    }
    if ("null".equalsIgnoreCase(string)) {
        return JsonValue.NULL;
    }
    try {
        return asNumber(string);
    } catch (Exception e) {
        throw new JsonParseException("Invalid value.");
    }
}
```### // next object assumes you have already seen the starting 
```java
// next object assumes you have already seen the starting {
private Map<String, JsonValue> nextObject() throws JsonParseException {
    Map<String, JsonValue> map = new HashMap<>();
    String key;
    while (true) {
        char c = nextToken();
        switch(c) {
            case 0:
                throw new JsonParseException("Text must end with '}'");
            case '}':
                return map;
            case '{':
            case '[':
                if (previous == '{') {
                    throw new JsonParseException("Cannot directly nest another Object or Array.");
                }
            // fall through
            default:
                key = nextString();
        }
        c = nextToken();
        if (c != ':') {
            throw new JsonParseException("Expected a ':' after a key.");
        }
        JsonValue value = nextValue();
        if (value != NULL || keepNulls) {
            map.put(key, value);
        }
        switch(nextToken()) {
            case ',':
                if (peekToken() == '}') {
                    // dangling comma
                    return map;
                }
                break;
            case '}':
                return map;
            default:
                throw new JsonParseException("Expected a ',' or '}'.");
        }
    }
}

The nextObject() method in the JsonParser class is used to parse a JSON object from a given input stream. It assumes that the starting { character has already been seen.

Here is a step-by-step description of what the method does:

  1. Create a new HashMap called map to store the key-value pairs of the JSON object.
  2. Start a while loop that continues until the method returns. This loop is used to iterate through each key-value pair in the JSON object.
  3. Get the next character from the input stream using the nextToken() method.
  4. Switch on the value of the character:
    • If the value is 0, throw a JsonParseException with the message "Text must end with '}'".
    • If the value is }, return the map, indicating that the end of the object has been reached.
    • If the value is { or [, check if the previous token was {. If it was, throw a JsonParseException with the message "Cannot directly nest another Object or Array."
    • For any other character, assume it is a key and assign it to the key variable using the nextString() method.
  5. Get the next character from the input stream and check if it is :. If it is not, throw a JsonParseException with the message "Expected a ':' after a key."
  6. Call the nextValue() method to parse the value of the key. Assign this value to the value variable.
  7. Check if the value is not null or if keepNulls flag is set to true. If either condition is true, add the key-value pair to the map using the put() method.
  8. Get the next character from the input stream.
  9. Switch on the value of the character:
    • If the value is , and the next token is }, return the map. This means there is a dangling comma at the end of the object.
    • If the value is ,, continue to the next iteration of the loop to process the next key-value pair.
    • If the value is }, return the map, indicating that the end of the object has been reached.
    • For any other character, throw a JsonParseException with the message "Expected a ',' or '}'."
  10. Repeat steps 3-9 until the end of the JSON object is reached.

Note: The exact behavior of some steps may depend on the specific implementation of the JsonParser class. This description assumes the provided code is the complete and correct implementation.

The method nextObject in the class JsonParser is used to parse the next JSON object from a JSON input. It assumes that the input starts with a { character, indicating the beginning of the object.

The method reads the input character by character and constructs a Map<String, JsonValue> to represent the key-value pairs of the JSON object. It iterates over the input until it encounters the closing } character, indicating the end of the object.

Inside the loop, the method checks each character and handles different cases accordingly:

  • If the character is not one of {, }, [, or ], it considers it as a key and calls the nextString method to parse the corresponding key string.
  • After parsing the key, the method expects to encounter a : character, indicating the separation between the key and the associated value.
  • The method then calls the nextValue method to parse the JSON value associated with the key.
  • If the parsed value is not NULL (or if the flag keepNulls is set to true), the method adds the key-value pair to the map.
  • After parsing a value, the method expects to encounter either , indicating more key-value pairs are present, or } indicating the end of the object. If a , is encountered and the next character is }, it means that a dangling comma is present, and the method returns the constructed map at that point.

Once the method reaches the end of the object, it returns the map containing the parsed key-value pairs.

Overall, this method allows the user to extract a JSON object from a JSON input stream and convert it into a Map<String, JsonValue> representation.

sequence diagram

private char nextToken()

private char nextToken() {
    peekToken();
    idx = nextIdx;
    nextIdx = -1;
    previous = current;
    current = next;
    next = 0;
    return current;
}

The nextToken() method in the JsonParser class is responsible for returning the next character token while parsing JSON content. Here is a step-by-step description of what the method does based on its body:

  1. The peekToken() method is called to determine the next token without consuming it.
  2. The current index (idx) is assigned to the previous index (nextIdx) to keep track of the position of the previous token.
  3. The next index (nextIdx) is set to -1 to indicate that it hasn't been determined yet.
  4. The current character (current) is assigned to the previous character (previous) to keep track of the previous token.
  5. The next character (next) is set to 0 as a placeholder for the next token.
  6. The value of the current character (current) is returned as the result of the method.

In summary, the nextToken() method updates the state of the parser, including the current and previous characters and their corresponding indices, and returns the current character as the next token.

The nextToken method in the JsonParser class is used to retrieve the next JSON token while parsing a JSON string.

Here is a brief description of what this method does based on its body:

  1. peekToken() is called to determine the type of the next token without consuming it.
  2. The index (idx) is updated to the value of nextIdx, which represents the starting position of the next token.
  3. nextIdx is set to -1, indicating that the starting position of the next token is not yet known.
  4. The current character (current) is preserved as the previous character.
  5. The next character (next) becomes the current character.
  6. The value of next is reset to 0, indicating that the next character has not yet been determined.
  7. The current character is returned.

This method allows the JSON parser to iterate through the JSON string, token by token, by updating the necessary variables to keep track of the current and next characters.

sequence diagram

private char nextChar()

private char nextChar() {
    previous = current;
    if (idx == len) {
        current = 0;
    } else {
        current = json[idx++];
    }
    next = 0;
    nextIdx = -1;
    return current;
}

Step-by-Step Description of the nextChar Method

  1. Set the previous character variable to the value of the current character.
  2. Check if the index (idx) is equal to the length of the json string.
    • If true, set the current character variable to 0.
    • If false, proceed to the next step.
  3. If the index is not equal to the length of the json string:
    • Set the current character variable to the character at the current index idx in the json string.
    • Increment the idx by 1.
  4. Set the next character variable to 0.
  5. Set the nextIdx variable to -1.
  6. Return the value of the current character.

The nextChar method, defined in the JsonParser class in the io.nats.client.support package, reads the next character from a JSON input string.

The method updates the previous variable to hold the value of the current character and then checks if idx (the current index) is equal to len (the length of the JSON input string). If idx is equal to len, it means that the method has reached the end of the JSON string and sets current to 0. Otherwise, the method sets current to the character at the idx index of the json string and increments idx.

The method also sets next to 0 and nextIdx to -1, indicating that there is no next character or next index. Finally, the method returns the value of the current character.

sequence diagram

private char peekToken()

private char peekToken() {
    if (nextIdx == -1) {
        nextIdx = idx;
        next = 0;
        while (nextIdx < len) {
            char c = json[nextIdx++];
            switch(c) {
                case ' ':
                case '\r':
                case '\n':
                case '\t':
                    continue;
            }
            return next = c;
        }
    }
    return next;
}

The peekToken method is defined in the io.nats.client.support.JsonParser class. It is used to retrieve the next character token in a JSON string without consuming it.

Here is a step-by-step description of what the peekToken method does based on its body:

  1. The method starts with a check for the value of nextIdx. If nextIdx is equal to -1, it means that the next character token has not been set yet.
  2. If nextIdx is -1, the method initializes nextIdx with the value of idx (which is the index of the current character token) and sets next to 0.
  3. Then a while loop is started, which continues until nextIdx is less than len (which represents the length of the JSON string).
  4. Inside the while loop, the method retrieves the next character c from the json array using the nextIdx++ expression. This increments nextIdx after retrieving the character.
  5. The switch statement considers the value of the retrieved character c.
  6. If c is a whitespace character (space, carriage return, newline, or tab), the loop continues without doing anything else.
  7. If c is not a whitespace character, then the method assigns c to next and returns its value as the next character token.
  8. If the while loop completes without finding a non-whitespace character, it means that the end of the JSON string has been reached.
  9. In that case, the method returns the value of next (which will be 0 if no non-whitespace character was found in the JSON string).

This peekToken method allows you to check the next character token in a JSON string without actually consuming it. This can be useful when parsing JSON and determining the structure or content of the JSON string.

The peekToken() method in the JsonParser class is used to peek at the next character in a JSON string without consuming it.

The method initializes a variable next to store the next character and nextIdx to keep track of the current index in the JSON string. If nextIdx is -1, it means that the method has not yet read the next character. In this case, the method iterates through the JSON string (json) starting from idx and checks each character using a switch statement.

If the character is a whitespace character (such as space, newline, carriage return, or tab), the method continues to the next character. Otherwise, the method sets next to the current character and increments nextIdx. The method then returns the character stored in next.

If nextIdx is not -1, it means that the method has already read the next character, so it simply returns the value stored in next.

Overall, the peekToken() method is responsible for peeking at the next non-whitespace character in a JSON string without consuming it.

// next string assumes you have already seen the starting quote

private String nextString() throws JsonParseException

// next string assumes you have already seen the starting quote
private String nextString() throws JsonParseException {
    StringBuilder sb = new StringBuilder();
    while (true) {
        char c = nextChar();
        switch(c) {
            case 0:
            case '\n':
            case '\r':
                throw new JsonParseException("Unterminated string.");
            case '\\':
                c = nextChar();
                switch(c) {
                    case 'b':
                        sb.append('\b');
                        break;
                    case 't':
                        sb.append('\t');
                        break;
                    case 'n':
                        sb.append('\n');
                        break;
                    case 'f':
                        sb.append('\f');
                        break;
                    case 'r':
                        sb.append('\r');
                        break;
                    case 'u':
                        sb.append(parseU());
                        break;
                    case '"':
                    case '\'':
                    case '\\':
                    case '/':
                        sb.append(c);
                        break;
                    default:
                        throw new JsonParseException("Illegal escape.");
                }
                break;
            default:
                if (c == '"') {
                    return sb.toString();
                }
                sb.append(c);
        }
    }
}
```### private char[] parseU() throws JsonParseException 
```java
private char[] parseU() throws JsonParseException {
    char[] a = new char[4];
    for (int x = 0; x < 4; x++) {
        a[x] = nextToken();
        if (a[x] == 0) {
            throw new JsonParseException("Illegal escape.");
        }
    }
    try {
        int code = Integer.parseInt("" + a[0] + a[1] + a[2] + a[3], 16);
        return Character.toChars(code);
    } catch (RuntimeException e) {
        throw new JsonParseException("Illegal escape.", e);
    }
}

The method parseU defined in class io.nats.client.support.JsonParser is responsible for parsing a Unicode escape sequence in a JSON string. Here is the step-by-step description of what this method is doing:

  1. It declares and initializes a char array a with a length of 4.
  2. It enters a for loop that iterates 4 times, with the loop variable x starting from 0 and incrementing by 1 in each iteration.
  3. Inside the loop, it calls the nextToken method and assigns the returned char value to the x-th index of a.
  4. It checks if the x-th element of a is equal to 0. If it is, it throws a JsonParseException with the message "Illegal escape."
  5. After the loop, it tries to parse the hexadecimal representation of the char array a as an integer.
    • It concatenates the char elements of a into a string, and then parses it as an integer using Integer.parseInt.
    • The parsed integer will represent a Unicode code point.
  6. It calls Character.toChars with the parsed code point to convert it into a char array representing the character(s) corresponding to the code point.
    • This is necessary because a Unicode code point can represent a single character or a surrogate pair that requires two char elements.
  7. It returns the resulting char array.

If any exception occurs during parsing or conversion, it catches a RuntimeException, wraps it in a JsonParseException with the message "Illegal escape," and rethrows the wrapped exception.

The parseU() method in the io.nats.client.support.JsonParser class is used to parse and decode a Unicode escape sequence in the JSON input.

Here's a breakdown of what the method does:

  1. It initializes a character array a with a length of 4.
  2. It iterates 4 times using a for loop, and in each iteration, it assigns the next token character to a[x].
  3. It checks if the assigned character is equal to 0; if it is, it throws a JsonParseException with the message "Illegal escape."
  4. It attempts to convert the 4 characters in a into an integer code by parsing them as a hexadecimal number.
  5. It uses the Character.toChars() method to convert the code into a character or characters (as an array).
  6. It returns the resulting character or characters.

If there is any exception encountered during this process, a JsonParseException with the message "Illegal escape." is thrown, and if provided, the original exception is included as the cause of the thrown exception.

sequence diagram

private JsonValue asNumber(String val) throws JsonParseException

private JsonValue asNumber(String val) throws JsonParseException {
    char initial = val.charAt(0);
    if ((initial >= '0' && initial <= '9') || initial == '-') {
        // decimal representation
        if (isDecimalNotation(val)) {
            // Use a BigDecimal all the time to keep the original
            // representation. BigDecimal doesn't support -0.0, ensure we
            // keep that by forcing a decimal.
            try {
                BigDecimal bd = new BigDecimal(val);
                if (initial == '-' && BigDecimal.ZERO.compareTo(bd) == 0) {
                    return new JsonValue(-0.0);
                }
                return new JsonValue(bd);
            } catch (NumberFormatException retryAsDouble) {
                // this is to support "Hex Floats" like this: 0x1.0P-1074
                try {
                    double d = Double.parseDouble(val);
                    if (Double.isNaN(d) || Double.isInfinite(d)) {
                        throw new JsonParseException("val [" + val + "] is not a valid number.");
                    }
                    return new JsonValue(d);
                } catch (NumberFormatException ignore) {
                    throw new JsonParseException("val [" + val + "] is not a valid number.");
                }
            }
        }
        // block items like 00 01 etc. Java number parsers treat these as Octal.
        if (initial == '0' && val.length() > 1) {
            char at1 = val.charAt(1);
            if (at1 >= '0' && at1 <= '9') {
                throw new JsonParseException("val [" + val + "] is not a valid number.");
            }
        } else if (initial == '-' && val.length() > 2) {
            char at1 = val.charAt(1);
            char at2 = val.charAt(2);
            if (at1 == '0' && at2 >= '0' && at2 <= '9') {
                throw new JsonParseException("val [" + val + "] is not a valid number.");
            }
        }
        BigInteger bi = new BigInteger(val);
        if (bi.bitLength() <= 31) {
            return new JsonValue(bi.intValue());
        }
        if (bi.bitLength() <= 63) {
            return new JsonValue(bi.longValue());
        }
        return new JsonValue(bi);
    }
    throw new JsonParseException("val [" + val + "] is not a valid number.");
}

The asNumber method in class io.nats.client.support.JsonParser is responsible for parsing a string representation of a number and converting it to a JsonValue object. Here is a step-by-step description of what the method does based on its body:

  1. Get the first character of the input string and store it in the variable initial.
  2. Check if the first character is a digit (0 to 9) or a hyphen (-).
  3. If the first character is a digit or a hyphen, proceed to the next steps. Otherwise, throw a JsonParseException with an error message indicating that the input string is not a valid number.
  4. Check if the number is represented in decimal notation by calling the isDecimalNotation method. If it is, continue to the next steps. If not, go to step 13.
  5. Try to create a BigDecimal object from the input string using new BigDecimal(val). This ensures that the original representation of the number is preserved. If the value of initial is - and the BigDecimal.ZERO is equal to the created BigDecimal object, create a new JsonValue object representing negative zero (-0.0). Otherwise, create a new JsonValue object with the BigDecimal value.
  6. If an exception of type NumberFormatException is caught during the BigDecimal creation, proceed to the next steps to handle other special cases.
  7. This part is to support "Hex Floats" like 0x1.0P-1074. Attempt to parse the input string as a double using Double.parseDouble(val).
  8. Check if the parsed double value is NaN (not a number) or Infinity. If it is, throw a JsonParseException with an error message indicating that the input string is not a valid number.
  9. If the parsed double value is valid, create a new JsonValue object with the double value.
  10. If an exception of type NumberFormatException is caught during the double parsing, throw a JsonParseException with an error message indicating that the input string is not a valid number.
  11. If the first character is 0 and the length of the input string is greater than 1, check if the second character is a digit (0 to 9). If it is, throw a JsonParseException with an error message indicating that the input string is not a valid number.
  12. If the first character is a hyphen (-) and the length of the input string is greater than 2, check if the second character is 0 and the third character is a digit (0 to 9). If it is, throw a JsonParseException with an error message indicating that the input string is not a valid number.
  13. Create a BigInteger object from the input string using new BigInteger(val).
  14. Check the bit length of the BigInteger object. If it is less than or equal to 31, create a new JsonValue object with the int value of the BigInteger.
  15. If the bit length of the BigInteger is less than or equal to 63, create a new JsonValue object with the long value of the BigInteger.
  16. For larger BigInteger values, create a new JsonValue object with the BigInteger value.
  17. If the first character of the input string is not a digit or a hyphen, throw a JsonParseException with an error message indicating that the input string is not a valid number.

The asNumber method in the JsonParser class is used to parse a string representation of a number and convert it into a JsonValue object.

Here's a brief overview of what the method does:

  1. It checks the first character of the input string to determine if it is a valid number or not.
  2. If the number is a decimal representation, it uses a BigDecimal to keep the original representation. It also handles cases like -0.0 by checking if the value is equal to zero and negative. If it is, it returns a JsonValue object representing -0.0.
  3. If the number is not a decimal representation, it checks for other special cases like "Hex Floats" and blocks certain items like 00 and 01 that Java number parsers treat as Octal.
  4. If the number passes all the checks, it converts it into a BigInteger object. If the bitLength of the BigInteger is less than or equal to 31, it returns a JsonValue object representing the number as an int. If the bitLength is less than or equal to 63, it returns a JsonValue object representing the number as a long. Otherwise, it returns a JsonValue object representing the number as a BigInteger.
  5. If the input string is not a valid number, it throws a JsonParseException with an appropriate error message.

Overall, the asNumber method handles various cases and provides a flexible way to parse and convert different types of numbers into a JsonValue object.

sequence diagram

Encoding

Encoding

The Encoding class is an abstract class that provides a framework for implementing different encoding algorithms. It serves as a base class for specific encoding classes and defines common properties and methods that are shared by these classes. Being an abstract class, it cannot be instantiated on its own. Instead, it provides a template for creating encoding classes that adhere to the specified structure and functionality.

public static char[] base32Encode(final byte[] input)

public static char[] base32Encode(final byte[] input) {
    int last = input.length;
    char[] charBuff = new char[(last + 7) * 8 / SHIFT];
    int offset = 0;
    int buffer = input[offset++];
    int bitsLeft = 8;
    int i = 0;
    while (bitsLeft > 0 || offset < last) {
        if (bitsLeft < SHIFT) {
            if (offset < last) {
                buffer <<= 8;
                buffer |= (input[offset++] & 0xff);
                bitsLeft += 8;
            } else {
                int pad = SHIFT - bitsLeft;
                buffer <<= pad;
                bitsLeft += pad;
            }
        }
        int index = MASK & (buffer >> (bitsLeft - SHIFT));
        bitsLeft -= SHIFT;
        charBuff[i] = BASE32_CHARS.charAt(index);
        i++;
    }
    int nonBlank;
    for (nonBlank = charBuff.length - 1; nonBlank >= 0; nonBlank--) {
        if (charBuff[nonBlank] != 0) {
            break;
        }
    }
    char[] retVal = new char[nonBlank + 1];
    System.arraycopy(charBuff, 0, retVal, 0, retVal.length);
    Arrays.fill(charBuff, '\0');
    return retVal;
}
```### public static byte[] base32Decode(final char[] input) 
```java
public static byte[] base32Decode(final char[] input) {
    byte[] bytes = new byte[input.length * SHIFT / 8];
    int buffer = 0;
    int next = 0;
    int bitsLeft = 0;
    for (int i = 0; i < input.length; i++) {
        int lookup = input[i] - '0';
        if (lookup < 0 || lookup >= BASE32_LOOKUP.length) {
            continue;
        }
        int c = BASE32_LOOKUP[lookup];
        buffer <<= SHIFT;
        buffer |= c & MASK;
        bitsLeft += SHIFT;
        if (bitsLeft >= 8) {
            bytes[next++] = (byte) (buffer >> (bitsLeft - 8));
            bitsLeft -= 8;
        }
    }
    return bytes;
}

Method: base32Decode

This method is defined in the class io.nats.client.support.Encoding. It takes in a character array as input and returns a byte array.

Steps:

  1. Initialize a byte array bytes with a length calculated as input.length * SHIFT / 8. (line 2)
  2. Initialize variables buffer, next, and bitsLeft to 0. (lines 3-5)
  3. Iterate through each character in the input array. (line 6)
  4. Calculate the index of the character in the BASE32_LOOKUP array by subtracting the ASCII value of '0' from the current character. (line 7)
  5. If the calculated index is invalid (less than 0 or greater than or equal to the length of BASE32_LOOKUP), skip to the next iteration. (line 8)
  6. Retrieve the value from the BASE32_LOOKUP array corresponding to the calculated index and store it in variable c. (line 9)
  7. Shift the content of buffer to the left by SHIFT bits. (line 10)
  8. Perform a bitwise OR operation between buffer and the lower MASK bits of c, and update buffer with the result. (line 11)
  9. Increment bitsLeft by SHIFT. (line 12)
  10. If bitsLeft is greater than or equal to 8, extract the most significant 8 bits from buffer and store them in the bytes array at the index next. (line 13)
    • Shift buffer to the right by (bitsLeft - 8) bits to get the 8 most significant bits.
    • Cast the result to a byte and store it in bytes[next].
    • Decrease bitsLeft by 8.
    • Increment next by 1.
  11. Repeat from step 3 for the next character in input.
  12. Return the bytes array. (line 19)

The method base32Decode in the class io.nats.client.support.Encoding is used to decode a base32 encoded input represented as a char array and return the decoded result as a byte array.

The method follows the base32 decoding algorithm by iteratively processing each character in the input array. It uses a lookup table to convert each character to its corresponding decimal value.

The decoding process involves shifting the bits of the decimal value into a buffer, accumulating bits until there are at least 8 bits available. Once there are 8 or more bits, the method stores the byte formed by the 8 most significant bits in the bytes array, and then adjusts the bitsLeft count accordingly.

This process continues until all characters in the input array have been processed, and finally, the resulting bytes array is returned as the decoded output.

sequence diagram

public static String jsonDecode(String s)

public static String jsonDecode(String s) {
    int len = s.length();
    StringBuilder sb = new StringBuilder(len);
    for (int x = 0; x < len; x++) {
        char ch = s.charAt(x);
        if (ch == '\\') {
            char nextChar = (x == len - 1) ? '\\' : s.charAt(x + 1);
            switch(nextChar) {
                case '\\':
                    ch = '\\';
                    break;
                case 'b':
                    ch = '\b';
                    break;
                case 'f':
                    ch = '\f';
                    break;
                case 'n':
                    ch = '\n';
                    break;
                case 'r':
                    ch = '\r';
                    break;
                case 't':
                    ch = '\t';
                    break;
                // Hex Unicode: u????
                case 'u':
                    if (x >= len - 5) {
                        ch = 'u';
                        break;
                    }
                    int code = Integer.parseInt("" + s.charAt(x + 2) + s.charAt(x + 3) + s.charAt(x + 4) + s.charAt(x + 5), 16);
                    sb.append(Character.toChars(code));
                    x += 5;
                    continue;
                default:
                    ch = nextChar;
                    break;
            }
            x++;
        }
        sb.append(ch);
    }
    return sb.toString();
}

The jsonDecode method in the Encoding class is used to decode a JSON-encoded string. Here is a step-by-step description of how this method works:

  1. The method takes a string s as input.
  2. It initializes a variable len with the length of the input string.
  3. It creates a StringBuilder object sb with a initial capacity of len.
  4. It starts a loop from x = 0 to len - 1.
  5. Inside the loop, it retrieves the character at index x of the input string using charAt() method, and assigns it to a variable ch.
  6. It checks if ch is the escape character ''.
  7. If ch is '', then it retrieves the next character nextChar. If x is equal to len - 1, it assigns a single quote ('') to nextChar.
  8. It then checks the value of nextChar using a switch statement.
    • If nextChar is '', it sets ch to ''.
    • If nextChar is 'b', it sets ch to a backspace character.
    • If nextChar is 'f', it sets ch to a form feed character.
    • If nextChar is 'n', it sets ch to a new line character.
    • If nextChar is 'r', it sets ch to a carriage return character.
    • If nextChar is 't', it sets ch to a tab character.
    • If nextChar is 'u', it parses the next four characters after 'u' as a hexadecimal number and converts it to the corresponding Unicode character. It then appends this character to the sb StringBuilder. The loop variable x is incremented by 5 to skip the four parsed hexadecimal characters and the 'u' character.
    • If nextChar is any other character, it assigns nextChar to ch.
    • The loop variable x is incremented by 1 before continuing to the next iteration of the loop.
  9. If ch is not '', it appends ch to the sb StringBuilder.
  10. After the loop finishes, it returns the contents of the sb StringBuilder as a string using the toString() method.

This jsonDecode method is used to replace the escape sequences in a JSON-encoded string with their original characters.

The jsonDecode method is a static method defined in the io.nats.client.support.Encoding class. It takes a String parameter s and returns a decoded JSON string.

Here's a breakdown of what the method does:

  • It initializes a StringBuilder sb to store the decoded string.
  • It iterates through each character in the input string s.
  • If the current character is a backlash ( \ ), it checks the next character to determine the escape sequence:
    • If the next character is also a backlash, it appends a backlash character to the sb.
    • If the next character is b, it appends a backspace character ( ) to the sb.
    • If the next character is f, it appends a form feed character ( ) to the sb.
    • If the next character is n, it appends a newline character ( '\n' ) to the sb.
    • If the next character is r, it appends a carriage return character ( '\r' ) to the sb.
    • If the next character is t, it appends a tab character ( '\t' ) to the sb.
    • If the next character is u, it expects the next 4 characters to be a hexadecimal Unicode code representing a character. It converts the code to a character using Character.toChars(code) and appends it to the sb. It increments the loop variable x by 5 to skip the next 4 characters.
    • If the next character doesn't match any of the above cases, it appends the next character as is to the sb.
    • It increments the loop variable x by 1 to skip the next character since it has already been processed as part of an escape sequence.
  • If the current character is not a backlash, it appends it as is to the sb.
  • Finally, it returns the decoded string by calling sb.toString().

The jsonDecode method essentially decodes JSON escape sequences in a given JSON string and returns the decoded string.

sequence diagram

public static StringBuilder jsonEncode(StringBuilder sb, String s)

public static StringBuilder jsonEncode(StringBuilder sb, String s) {
    int len = s.length();
    for (int x = 0; x < len; x++) {
        char ch = s.charAt(x);
        switch(ch) {
            case '"':
                sb.append("\\\"");
                break;
            case '\\':
                sb.append("\\\\");
                break;
            case '\b':
                sb.append("\\b");
                break;
            case '\f':
                sb.append("\\f");
                break;
            case '\n':
                sb.append("\\n");
                break;
            case '\r':
                sb.append("\\r");
                break;
            case '\t':
                sb.append("\\t");
                break;
            case '/':
                sb.append("\\/");
                break;
            default:
                if (ch < ' ') {
                    sb.append(String.format("\\u%04x", (int) ch));
                } else {
                    sb.append(ch);
                }
                break;
        }
    }
    return sb;
}
```### public static String uriDecode(String source) 
```java
public static String uriDecode(String source) {
    try {
        return URLDecoder.decode(source.replace("+", "%2B"), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return source;
    }
}

Method: uriDecode

This method is defined in the io.nats.client.support.Encoding class and is responsible for URI decoding of a given input string.

Parameters

  • source (String): The input string that needs to be decoded.

Return Value

  • String: The URI decoded string.

Steps

  1. Replace all occurrences of the + character in the source string with %2B.
  2. Use the URLDecoder.decode() method to perform URL decoding on the modified source string.
  3. Specify the encoding to use as "UTF-8".
  4. If the specified encoding is unsupported and an UnsupportedEncodingException is thrown, catch the exception and return the original source string.
  5. Return the decoded string obtained from step 2.

Example Usage

String input = "Hello%20World%21";
String decoded = Encoding.uriDecode(input);
System.out.println(decoded);

// Output: "Hello World!"

In the example above, the input string is URI encoded with "%20" representing a space character. The uriDecode method is called on the input string, which decodes it and returns the decoded string "Hello World!". Finally, the decoded string is printed to the console.

The uriDecode method defined in the Encoding class within the io.nats.client.support package is used to decode a URI-encoded string. It takes a source string as input and replaces any occurrences of the "+" character with "%2B". It then uses the URLDecoder.decode method to decode the modified source string using the "UTF-8" character encoding. If an UnsupportedEncodingException occurs during this decoding process, the original source string is returned as is. The method returns the decoded string.

sequence diagram

NatsUri

NatsUri

The NatsUri class is a public class that represents a URI for a NATS (North American Trading System) connection. It allows for the parsing and manipulation of NATS URIs, making it easier to connect to and communicate with a NATS messaging system.

private void postConstruct()

private void postConstruct() {
    String s = uri.getScheme().toLowerCase();
    isSecure = SECURE_PROTOCOLS.contains(s);
    isWebsocket = WSS_PROTOCOLS.contains(s);
    s = uri.getHost();
    hostIsIpAddress = IPV4_RE.matcher(s).matches() || s.startsWith("[") && s.endsWith("]");
}

Method: postConstruct()

The postConstruct() method defined in class io.nats.client.support.NatsUri performs the following steps:

  1. Converts the scheme of the provided URI to lowercase and assigns it to a local variable s.
  2. Checks if the value of s is present in the SECURE_PROTOCOLS list.
    • If present, sets the isSecure boolean variable to true.
    • If not present, sets the isSecure boolean variable to false.
  3. Checks if the value of s is present in the WSS_PROTOCOLS list.
    • If present, sets the isWebsocket boolean variable to true.
    • If not present, sets the isWebsocket boolean variable to false.
  4. Retrieves the host from the provided URI and assigns it to the variable s.
  5. Checks if the host is an IP address using regular expression matching or if the host is enclosed within square brackets ([ and ]).
    • If the above condition is met, sets the hostIsIpAddress boolean variable to true.
    • If the condition is not met, sets the hostIsIpAddress boolean variable to false.

Note: The purpose and behavior of the above method is explained based on the provided code snippet. Additional context or information about other parts of the code may be necessary for a comprehensive understanding.

The postConstruct method in the io.nats.client.support.NatsUri class is used to initialize the instance variables isSecure, isWebsocket, and hostIsIpAddress based on the values of the uri object.

First, it converts the scheme of the URI to lowercase and checks if it exists in the SECURE_PROTOCOLS collection. If it does, the isSecure variable is set to true.

Next, it checks if the scheme exists in the WSS_PROTOCOLS collection. If it does, the isWebsocket variable is set to true.

Lastly, it assigns the value of the host in the URI to the variable s. It uses regular expressions to determine if the host is an IP address or if it is surrounded by square brackets (for IPv6 addresses). If either condition is true, the hostIsIpAddress variable is set to true.

sequence diagram

private Helper parse(String inUrl, boolean allowTryPrefixed, String prefix) throws URISyntaxException

private Helper parse(String inUrl, boolean allowTryPrefixed, String prefix) throws URISyntaxException {
    Helper helper = new Helper();
    try {
        helper.url = inUrl.trim();
        helper.uri = new URI(helper.url);
        return helper;
    } catch (URISyntaxException e) {
        if (allowTryPrefixed && e.getMessage().contains(URI_E_ALLOW_TRY_PREFIXED)) {
            // [4]
            return tryPrefixed(helper, prefix);
        } else {
            // [5]
            throw e;
        }
    }
}

The parse method is defined in the NatsUri class and takes in three parameters: inUrl, allowTryPrefixed, and prefix. It also throws a URISyntaxException.

The purpose of this method is to parse a given URL string (inUrl) and create a Helper object containing the parsed URL (uri) and the original URL (url).

Here is a step-by-step description of what this method does based on its body:

  1. Create a new Helper object called helper.

  2. Trim the input URL string (inUrl) and assign it to the url field of the helper object.

  3. Create a new URI object by passing the url field of the helper object to the URI constructor and assign it to the uri field of the helper object.

  4. Try to return the helper object. However, if an URISyntaxException is caught and the allowTryPrefixed parameter is true and the exception message contains a certain string (URI_E_ALLOW_TRY_PREFIXED), execute the following steps: a. Return the result of calling the tryPrefixed method with the helper object and the prefix parameter as arguments. This method will attempt to parse the URL again with a prefix.

  5. If step 4 did not execute (i.e., no exception was caught or the conditions were not met), throw the caught URISyntaxException.

In summary, the parse method takes a URL string, trims it, parses it into a URI object, and returns a Helper object containing the parsed URL. If an exception is caught and certain conditions are met, it tries to parse the URL again with a prefix. Otherwise, it rethrows the caught exception.

The parse method in the NatsUri class is used to parse a given URL into a Helper object. The method takes the input URL as a parameter and performs the following steps:

  1. The input URL is trimmed and assigned to the url field of the Helper object.
  2. The inUrl is transformed into a URI object and assigned to the uri field of the Helper object.
  3. The Helper object is returned.

If an exception of type URISyntaxException occurs during the parsing process, the method handles it as follows:

  1. If the allowTryPrefixed flag is set to true and the exception message contains a specific string URI_E_ALLOW_TRY_PREFIXED, the method executes the tryPrefixed method, passing the helper and prefix as parameters. The value returned by the tryPrefixed method is then returned by the parse method.
  2. If the above condition is not met or the allowTryPrefixed flag is set to false, the original exception is rethrown.

In summary, the parse method is responsible for parsing a URL and returning a Helper object. It also handles any exceptions that occur during the parsing process, allowing for optional additional parsing attempts based on certain conditions.

sequence diagram

public static String join(String delimiter, List uris)

public static String join(String delimiter, List<NatsUri> uris) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < uris.size(); i++) {
        if (i > 0) {
            sb.append(delimiter);
        }
        sb.append(uris.get(i).toString());
    }
    return sb.toString();
}

Method: join

Description

This method is used to join a list of NatsUri objects into a single string, separated by a delimiter.

Parameters

  • delimiter : String - The delimiter to be used for separating the joined strings.
  • uris : List - The list of NatsUri objects to be joined.

Returns

  • String - The joined string.

Algorithm

  1. Create a StringBuilder object, sb, to store the joined string.
  2. Iterate through the uris list using a for loop.
  3. Inside the loop, check if the current index (i) is greater than 0.
  4. If i is greater than 0, append the delimiter to the sb StringBuilder object.
  5. Append the NatsUri object at index i of the uris list to the sb StringBuilder object.
  6. Outside the loop, convert the sb StringBuilder object to a string using the toString() method and return the result.

Sample Usage

List<NatsUri> uris = new ArrayList<>();
uris.add(new NatsUri("nats://localhost:4222"));
uris.add(new NatsUri("nats://localhost:5222"));
uris.add(new NatsUri("nats://localhost:6222"));

String joinedString = NatsUri.join(",", uris);
System.out.println(joinedString);

Output:

nats://localhost:4222,nats://localhost:5222,nats://localhost:6222

The join method in the NatsUri class is a static method that takes a delimiter and a list of NatsUri objects as input parameters. It returns a string that represents the concatenation of the toString() representation of each NatsUri object in the list, separated by the delimiter.

To accomplish this, the method creates a StringBuilder object and iterates over the uris list. If the current index is greater than 0, the delimiter is appended to the StringBuilder. Then, the toString() representation of the NatsUri at the current index is appended to the StringBuilder. Finally, the method returns the string representation of the StringBuilder using toString() method.

In summary, the join method in the NatsUri class is used to join a list of NatsUri objects into a single string, separated by a specified delimiter.

sequence diagram

JsonParseException

JsonParseException

The JsonParseException class is a subclass of IOException. It is used to represent an exception that occurs when there is an error parsing a JSON (JavaScript Object Notation) document. This class provides additional information and methods specifically related to handling parse errors in JSON.

ConsumerUtils

ConsumerUtils

The ConsumerUtils class is an abstract class that provides utility methods for consumers. It serves as a base class for other classes and cannot be instantiated directly. The class encapsulates various functionality related to consumer operations, allowing software engineers to streamline and enhance their code when working with consumers.

NatsRequestCompletableFuture

NatsRequestCompletableFuture

This NatsRequestCompletableFuture class is an internal class that extends the CompletableFuture class. It is only made public for access.

WebsocketFrameHeader

WebsocketFrameHeader

WebsocketFrameHeader is a public class that represents the header of a WebSocket frame. It provides the necessary information about the frame, such as the frame type, payload length, and masking key. The header is an integral component in the process of sending and receiving WebSocket frames, facilitating the communication between a client and a server.

public WebsocketFrameHeader withMask(int maskingKey)

public WebsocketFrameHeader withMask(int maskingKey) {
    this.mask = true;
    this.maskingKey = maskingKey;
    this.maskingKeyOffset = 0;
    return this;
}

The method withMask in the WebsocketFrameHeader class is used to enable masking for a WebSocket frame and sets the masking key for the frame. Here is a step-by-step description of what the method does:

  1. It takes an integer parameter maskingKey as input.
  2. It sets the mask field of the WebsocketFrameHeader object to true, indicating that masking is enabled for the frame.
  3. It assigns the value of the maskingKey parameter to the maskingKey field of the WebsocketFrameHeader object.
  4. It sets the maskingKeyOffset field of the WebsocketFrameHeader object to 0.
  5. It returns the updated WebsocketFrameHeader object.

The withMask method essentially enables masking for a WebSocket frame by setting the necessary fields in the WebsocketFrameHeader object. The masking key is used to encode the frame payload for security purposes.

The withMask method in the WebsocketFrameHeader class is used to set the masking key for a websocket frame header. When a websocket frame is sent, it can be optionally masked for security reasons. The withMask method allows the developer to specify the masking key to be used for masking the frame data. The method sets the mask flag to true, assigns the specified masking key to the maskingKey variable, and sets the maskingKeyOffset to 0. Finally, it returns the updated WebsocketFrameHeader object.

sequence diagram

public int filterPayload(byte[] buffer, int offset, int length)

public int filterPayload(byte[] buffer, int offset, int length) {
    length = Math.min(length, payloadLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) payloadLength);
    payloadLength -= length;
    if (mask) {
        for (int i = 0; i < length; i++) {
            int key = 0xFF & (maskingKey >> (8 * (7 - maskingKeyOffset)));
            buffer[offset + i] ^= key;
            maskingKeyOffset = (maskingKeyOffset + 1) % 8;
        }
    }
    return length;
}

The filterPayload method in the WebsocketFrameHeader class is responsible for filtering the payload data in a WebSocket frame.

Here is a step-by-step breakdown of what the method is doing:

  1. The method takes in three parameters: buffer, offset, and length. These parameters represent the payload data, the starting offset position in the buffer, and the length of the payload data, respectively.

  2. The method calculates the actual length of the payload data to filter. It uses the Math.min method to ensure that the length does not exceed the value of payloadLength or the maximum value of an int. The payloadLength variable represents the total length of the payload data.

  3. The payloadLength is decremented by the filtered length to keep track of the remaining payload data.

  4. If the WebSocket frame is masked (i.e., the mask flag is true), the method proceeds to unmask the payload data. It iterates over each byte in the payload data, applying a XOR operation with an individual byte from the maskingKey. The maskingKeyOffset is used to determine which byte of the maskingKey to use for each iteration.

  5. The method increments the maskingKeyOffset by 1, wrapping around to zero when it reaches the value of 7, to ensure that the bytes from the maskingKey are applied in a sequential order.

  6. Finally, the method returns the filtered length of the payload data.

This method is typically called when processing WebSocket frames to extract the payload data while handling the frame-specific details such as masking.

The filterPayload method in io.nats.client.support.WebsocketFrameHeader class is used to filter the payload data by manipulating the provided input buffer.

The method takes in three parameters: buffer (the input byte array), offset (the starting position within the buffer), and length (the number of bytes to filter).

First, the method ensures that length does not exceed the remaining payload length by comparing it to payloadLength. If payloadLength is greater than Integer.MAX_VALUE, length is set to Integer.MAX_VALUE; otherwise, it is set to the value of payloadLength.

Next, if mask is true, the method iterates over each byte in the range of offset to offset + length - 1. It XORs each byte in the buffer with a corresponding mask key. The mask key is obtained by shifting the maskingKey (an 8-byte mask key) and applying bitwise AND with 0xFF. The maskingKeyOffset is updated to keep track of the current byte in the mask key.

Finally, the method returns the filtered length.

Overall, this method is responsible for filtering the payload data by applying a masking key (if applicable) to the input buffer.

sequence diagram

public int size()

public int size() {
    int size = 2;
    if (payloadLength > 0xFFFF) {
        size += 8;
    } else if (payloadLength > 125) {
        size += 2;
    }
    if (mask) {
        size += 4;
    }
    return size;
}

Step-by-Step Description of the size Method in WebsocketFrameHeader

The size method in the WebsocketFrameHeader class is responsible for determining the size of a websocket frame header based on the values specified in its BODY. Here is a step-by-step description of how the size method works:

  1. The method initializes the size variable with a value of 2. This is because a websocket frame header always has a minimum size of 2 bytes.

  2. The method checks if the payloadLength is greater than 0xFFFF (65535 in decimal). This is the maximum length a payload can have without needing additional bytes to represent the length.

    a. If the payloadLength is greater than 0xFFFF, it means that the payload length requires 8 additional bytes to be represented.

    b. In this case, the size variable is incremented by 8.

  3. If the payloadLength is not greater than 0xFFFF, the method checks if it is greater than 125.

    a. If the payloadLength is greater than 125, it means that the payload length requires 2 additional bytes to be represented.

    b. In this case, the size variable is incremented by 2.

  4. The method then checks if the mask flag is set. This flag indicates whether the payload is masked or not.

    a. If the mask flag is set to true, it means that the payload is masked and requires an additional 4 bytes to represent the masking key.

    b. In this case, the size variable is incremented by 4.

  5. Finally, the size variable is returned, which represents the total size of the websocket frame header based on the values specified in the BODY.

Note: The size method assumes that the payloadLength and mask variables have already been initialized with the correct values.

The size method in the io.nats.client.support.WebsocketFrameHeader class calculates the size of the WebSocket frame header based on the specified parameters in its body.

The method first initializes the size variable to 2. It then checks if the payloadLength is greater than 0xFFFF (65535). If it is, it increments the size by 8.

If the payloadLength is not greater than 0xFFFF, the method checks if it is greater than 125. If it is, the size is incremented by 2.

Next, the method checks if the mask flag is set. If it is, the size is further incremented by 4.

Finally, the method returns the calculated size.

This size method is used to determine the total size of the WebSocket frame header, which includes the length of the payload and any additional header fields such as the masking key.

sequence diagram

public static int size(byte[] buffer, int offset)

public static int size(byte[] buffer, int offset) {
    int size = 2;
    if (0 != (buffer[offset + 1] & 0x80)) {
        // mask adds 4 required bytes.
        size += 4;
    }
    switch(buffer[offset + 1] & 0x7F) {
        case 126:
            size += 2;
            break;
        case 127:
            size += 8;
            break;
    }
    return size;
}

The size(byte[] buffer, int offset) method in the WebsocketFrameHeader class is responsible for determining the size of the WebSocket frame based on the provided buffer and offset.

Here is a step-by-step description of how the method works:

  1. The method starts by initializing the size variable with a value of 2. This is because every WebSocket frame has a minimum size of 2 bytes.

  2. The method then checks if the most significant bit of the second byte in the buffer (at the given offset) is set to 1. This bit is used to indicate whether the frame payload is masked or not. If the bit is set (i.e., not equal to 0), it means that the payload is masked and an additional 4 bytes are required. In this case, the size is incremented by 4.

  3. Next, the method examines the least significant 7 bits of the second byte in the buffer (at the given offset). These bits represent the payload length. Based on the value of these bits, the method takes different actions:

    a. If the value is 126 (i.e., the payload length is encoded in the next two bytes), the size is incremented by 2 to account for these additional bytes.

    b. If the value is 127 (i.e., the payload length is encoded in the next eight bytes), the size is incremented by 8 to account for these additional bytes.

  4. Finally, the method returns the calculated size value, which represents the total size of the WebSocket frame.

By following this step-by-step process, the size(byte[] buffer, int offset) method accurately calculates the size of a WebSocket frame based on the provided buffer and offset.

The method size in class io.nats.client.support.WebsocketFrameHeader is responsible for determining the size of a WebSocket frame.

The method takes in a byte array buffer and an offset value.

First, it initializes the size variable to 2, which accounts for the initial 2 bytes of WebSocket frame header.

Then, it checks if the second byte in the buffer has the most significant bit (0x80) set. If it is set, it means that a masking key is present in the frame, and 4 additional bytes are required, so it increments the size by 4.

Next, it examines the value of the last 7 bits of the second byte to determine the payload length.

If the last 7 bits are equal to 126, it means that the payload length is stored in the next 2 bytes. In this case, the size is incremented by 2.

If the last 7 bits are equal to 127, it means that the payload length is stored in the next 8 bytes. In this case, the size is incremented by 8.

Finally, the method returns the calculated size.

sequence diagram

public int read(byte[] buffer, int offset, int length)

public int read(byte[] buffer, int offset, int length) {
    if (length < size()) {
        return 0;
    }
    int startOffset = offset;
    buffer[offset++] = byte0;
    if (payloadLength > 0xFFFF) {
        buffer[offset++] = (byte) (127 | (mask ? 0x80 : 0));
        // 64 bit length
        buffer[offset++] = (byte) ((payloadLength >> 56) & 0xFF);
        buffer[offset++] = (byte) ((payloadLength >> 48) & 0xFF);
        buffer[offset++] = (byte) ((payloadLength >> 40) & 0xFF);
        buffer[offset++] = (byte) ((payloadLength >> 32) & 0xFF);
        buffer[offset++] = (byte) ((payloadLength >> 24) & 0xFF);
        buffer[offset++] = (byte) ((payloadLength >> 16) & 0xFF);
        buffer[offset++] = (byte) ((payloadLength >> 8) & 0xFF);
        buffer[offset++] = (byte) (payloadLength & 0xFF);
    } else if (payloadLength > 125) {
        buffer[offset++] = (byte) (126 | (mask ? 0x80 : 0));
        // 16 bit length
        buffer[offset++] = (byte) (payloadLength >> 8);
        buffer[offset++] = (byte) (payloadLength & 0xFF);
    } else {
        buffer[offset++] = (byte) (payloadLength | (mask ? 0x80 : 0));
    }
    if (mask) {
        buffer[offset++] = (byte) ((maskingKey >> 24) & 0xFF);
        buffer[offset++] = (byte) ((maskingKey >> 16) & 0xFF);
        buffer[offset++] = (byte) ((maskingKey >> 8) & 0xFF);
        buffer[offset++] = (byte) (maskingKey & 0xFF);
    }
    return offset - startOffset;
}

The read() method in the WebsocketFrameHeader class is responsible for reading the WebSocket frame header data into a byte array buffer. Here is a step-by-step description of what this method does:

  1. Check if the given length is less than the size of the WebSocket frame header. If it is, return 0 (indicating that no data was read).

  2. Initialize the startOffset variable with the value of offset. This will be used to calculate the number of bytes read.

  3. Write the byte0 value to the buffer at the position specified by offset. Increment offset by 1.

  4. Check if the payloadLength is greater than 0xFFFF (65,535 in decimal). If it is, this indicates a payload length larger than can be represented in 16 bits.

  5. If the payload length is larger than 65,535, set the appropriate value in the buffer at offset to indicate the extended payload length. Increment offset by 1.

  6. Write the 64-bit payload length to the buffer at positions offset to offset + 8. The payload length is broken down into 8 bytes, each representing a different part of the 64-bit value. Increment offset by 8.

  7. If the payload length is between 126 and 65,535 (inclusive), set the appropriate value in the buffer at the position specified by offset. Increment offset by 1.

  8. If the payload length is less than or equal to 125, set the appropriate value in the buffer at the position specified by offset. Increment offset by 1.

  9. If the mask flag is set, write the 32-bit masking key to the buffer at positions offset to offset + 3. The masking key is broken down into 4 bytes, each representing a different part of the 32-bit value. Increment offset by 4.

  10. Calculate the number of bytes read by subtracting startOffset from the current value of offset.

  11. Return the calculated number of bytes read.

Note: The byte0, payloadLength, and maskingKey variables, which are used in the method, are not defined in the provided code snippet. They should be declared and initialized elsewhere in the class.

The read method in the WebsocketFrameHeader class is used to read and format the header of a WebSocket frame. The method takes in a byte array buffer, an offset value, and a length value. It fills the buffer array with the appropriate header values based on the size and payload length of the frame.

Here's a breakdown of what the method does:

  1. It checks if the length provided is sufficient to accommodate the size of the frame. If not, it returns 0.

  2. It sets the initial offset and stores the first byte of the frame header in the buffer.

  3. If the payload length is greater than 0xFFFF (more than 65535 bytes), it sets the appropriate flag in the header and stores the payload length as a 64-bit value in the buffer. The payload length is split into 8 bytes and stored in the buffer array.

  4. If the payload length is between 126 and 65535 bytes, it sets the appropriate flag in the header and stores the payload length as a 16-bit value in the buffer. The payload length is split into 2 bytes and stored in the buffer array.

  5. If the payload length is less than or equal to 125 bytes, it sets the payload length directly in the header of the buffer.

  6. If the masking flag is set, it stores the masking key (used for data masking during transmission) in the buffer. The masking key is split into 4 bytes and stored in the buffer array.

  7. Finally, it returns the difference between the final offset and the starting offset, indicating the number of bytes written to the buffer.

The read method is responsible for populating the buffer array with the appropriate values to construct the header of a WebSocket frame.

sequence diagram

public int write(byte[] buffer, int offset, int length)

public int write(byte[] buffer, int offset, int length) {
    // Sufficient remainder?
    if (length < 2) {
        return 0;
    }
    int size = size(buffer, offset);
    if (size > length) {
        return 0;
    }
    byte0 = buffer[offset++];
    mask = 0 != (buffer[offset] & 0x80);
    payloadLength = buffer[offset] & 0x7F;
    offset++;
    if (126 == payloadLength) {
        payloadLength = 0;
        for (int i = 0; i < 2; i++) {
            payloadLength <<= 8;
            payloadLength |= buffer[offset++] & 0xFF;
        }
    } else if (127 == payloadLength) {
        payloadLength = 0;
        for (int i = 0; i < 8; i++) {
            payloadLength <<= 8;
            payloadLength |= buffer[offset++] & 0xFF;
        }
    }
    if (mask) {
        maskingKey = 0;
        maskingKeyOffset = 0;
        for (int i = 0; i < 4; i++) {
            maskingKey <<= 8;
            maskingKey |= buffer[offset++] & 0xFF;
        }
    }
    return size;
}

The write method described here is defined in the WebsocketFrameHeader class in the io.nats.client.support package.

Based on the provided body of the method, here is the step-by-step description of what it does:

  1. Check if the length parameter is less than 2. If it is, return 0.
  2. Calculate the size based on the buffer and offset. This is done by calling another method called size (not shown in the provided body).
  3. Check if the calculated size is greater than the length. If it is, return 0.
  4. Assign the next byte in the buffer at offset to byte0.
  5. Check if the most significant bit (bit 7) of the next byte in the buffer at offset is set (1). If it is, set the mask flag to true.
  6. Set payloadLength to the least significant 7 bits of the next byte in the buffer at offset.
  7. Increment offset by 1.
  8. If the payloadLength is 126:
    • Reset payloadLength to 0.
    • Iterate over the next 2 bytes in the buffer starting from the updated offset.
    • Concatenate the 8 bits from each byte to form a 16-bit value and assign it to payloadLength.
    • Increment offset by 2.
  9. If the payloadLength is 127:
    • Reset payloadLength to 0.
    • Iterate over the next 8 bytes in the buffer starting from the updated offset.
    • Concatenate the 8 bits from each byte to form a 64-bit value and assign it to payloadLength.
    • Increment offset by 8.
  10. If mask is true:
    • Reset maskingKey and maskingKeyOffset to 0.
    • Iterate over the next 4 bytes in the buffer starting from the updated offset.
    • Concatenate the 8 bits from each byte to form a 32-bit value and assign it to maskingKey.
    • Increment offset by 4.
  11. Finally, return the calculated size.

Please note that there may be additional code in the WebsocketFrameHeader class that could affect the behavior and functionality of this method. The code provided here only describes the logic within the write method itself.

The method write in the WebsocketFrameHeader class is used to write a Websocket frame header into a byte array.

Here is a step-by-step breakdown of what the method does:

  1. It first checks if the length of the buffer is less than 2. If it is, it returns 0, indicating that no frame header was written.

  2. It calculates the size of the frame header using another method called size.

  3. It checks if the calculated size is greater than the length provided. If it is, it returns 0, indicating that no frame header was written.

  4. It reads the first byte from the buffer and assigns it to byte0.

  5. It checks if the most significant bit (MSB) of the next byte (offset byte) is set. If it is, it sets the mask flag to true, indicating that the payload is masked.

  6. It extracts the payload length from the offset byte by performing a bitwise AND operation with 0x7F.

  7. It increments the offset to move to the next byte in the buffer.

  8. If the payload length is 126, it reads the next 2 bytes from the buffer and combines them to form the actual payload length.

  9. If the payload length is 127, it reads the next 8 bytes from the buffer and combines them to form the actual payload length.

  10. If the payload is masked (mask flag is true), it reads the next 4 bytes from the buffer and combines them to form the masking key.

  11. Finally, it returns the size of the frame header.

Note: The method assumes that the buffer provided has enough space to accommodate the frame header.

sequence diagram

JsonUtils

JsonUtils

The JsonUtils class is an abstract class that provides internal helpers for parsing JSON. It includes read helpers that are deprecated and recommends using the JsonParser instead.

/* ensures cannot be constructed */

// ---------------------------------------------------------------------------------------------------- // BUILD A STRING OF JSON // ---------------------------------------------------------------------------------------------------- public static StringBuilder beginJson()

/* ensures cannot be constructed */
// ----------------------------------------------------------------------------------------------------
// BUILD A STRING OF JSON
// ----------------------------------------------------------------------------------------------------
public static StringBuilder beginJson() {
    return new StringBuilder("{");
}

The beginJson method is a static method defined in the JsonUtils class in the io.nats.client.support package. It takes no arguments and returns a StringBuilder object.

Here is the step-by-step description of what the beginJson method is doing based on its body:

  1. The method starts with a comment stating that it ensures the method cannot be constructed. This means that the method is declared as private or a static utility and cannot be instantiated.

  2. The method starts building a string of JSON by creating a new StringBuilder object.

  3. The beginJson method sets the initial character of the JSON string as an opening curly brace {. This indicates the start of a JSON object.

  4. Finally, the method returns the StringBuilder object that represents the beginning of the JSON string.

Note: The provided description is based solely on the information given in the body of the beginJson method. The actual functionality and purpose of the method may depend on its usage and other parts of the codebase.

The beginJson method in the JsonUtils class of the io.nats.client.support package returns a StringBuilder object initialized with a starting curly brace '{'. This method is used to build a string representation of JSON by appending elements to the StringBuilder.

sequence diagram

public static StringBuilder endJson(StringBuilder sb)

public static StringBuilder endJson(StringBuilder sb) {
    int lastIndex = sb.length() - 1;
    if (sb.charAt(lastIndex) == ',') {
        sb.setCharAt(lastIndex, '}');
        return sb;
    }
    sb.append("}");
    return sb;
}

The endJson method in the JsonUtils class is used to complete the construction of a JSON string by adding the closing brace '}' at the end.

The method takes a StringBuilder object sb as input and modifies it as follows:

  1. It retrieves the index of the last character in the StringBuilder using sb.length() - 1.
  2. It checks if the last character of the StringBuilder is a comma ',' by using sb.charAt(lastIndex) == ','.
  3. If the last character is a comma, it replaces it with a closing brace '}' by using sb.setCharAt(lastIndex, '}').
    • This is done to remove the trailing comma which is not valid in JSON syntax.
  4. If the last character is not a comma, it appends the closing brace '}' to the StringBuilder using sb.append("}").
    • This is done to add the closing brace at the end of the JSON string.

Finally, the method returns the modified StringBuilder object sb.

Overall, the purpose of the endJson method is to ensure that the JSON string being constructed is correctly and completely formatted by adding the closing brace '}' if it is missing, and by removing any trailing comma ',' if present.

The endJson method, defined in the JsonUtils class in the io.nats.client.support package, is used to correctly format the end of a JSON string.

The method takes a StringBuilder parameter sb and performs the following operations:

  1. It retrieves the index of the last character in the sb string.
  2. If the last character is a comma (,), it replaces it with a closing brace (}) to complete the JSON object structure, and returns the modified StringBuilder object.
  3. If the last character is not a comma, it appends a closing brace (}) to the sb string to complete the JSON object structure, and returns the modified StringBuilder object.

Overall, the endJson method ensures that the end of a JSON string is properly formatted by adding a closing brace (}) if necessary.

sequence diagram

public static StringBuilder endArray(StringBuilder sb)

public static StringBuilder endArray(StringBuilder sb) {
    int lastIndex = sb.length() - 1;
    if (sb.charAt(lastIndex) == ',') {
        sb.setCharAt(lastIndex, ']');
        return sb;
    }
    sb.append("]");
    return sb;
}

Method Name: endArray(StringBuilder sb)

Class: io.nats.client.support.JsonUtils

Description:

The endArray method is used to complete an array in a JSON string representation. It takes a StringBuilder as its parameter and returns the updated StringBuilder with the array closing bracket added.

Steps:

  1. Get the index of the last character in the StringBuilder by subtracting 1 from the length of the StringBuilder.
  2. Check if the last character in the StringBuilder is a comma (',') by comparing it with ',' using the charAt method on the StringBuilder.
  3. If the last character is a comma, replace it with a closing bracket (']') using the setCharAt method on the StringBuilder.
  4. Return the updated StringBuilder.
  5. If the last character is not a comma, append a closing bracket (']') to the StringBuilder using the append method.
  6. Return the updated StringBuilder.

The endArray method, defined in the io.nats.client.support.JsonUtils class, is used to properly close an array in a JSON string.

It takes a StringBuilder as input and checks if the last character of the StringBuilder is a comma (','), indicating that there are more items in the array. If it is a comma, the method replaces it with a closing bracket (']') to close the array and returns the StringBuilder.

If the last character is not a comma, the method appends a closing bracket to the StringBuilder and returns it.

Overall, the endArray method ensures that the JSON string is well-formed by closing the array properly.

sequence diagram

public static void addRawJson(StringBuilder sb, String fname, String json)

public static void addRawJson(StringBuilder sb, String fname, String json) {
    if (json != null && json.length() > 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON);
        sb.append(json);
        sb.append(COMMA);
    }
}

addRawJson Method Description

The addRawJson method is defined in the JsonUtils class, located in the io.nats.client.support package.

Method Signature

public static void addRawJson(StringBuilder sb, String fname, String json)

Method Description

The purpose of the addRawJson method is to add raw JSON data to a provided StringBuilder in a specific format. It takes three parameters:

  • sb: The StringBuilder object to which the JSON data is added.
  • fname: A string representing the field name of the JSON data.
  • json: A string containing the raw JSON data to be added.

The method performs the following steps:

  1. Checks if the json parameter is not null and has a length greater than 0.
  2. If the json parameter meets the conditions from step 1, the following actions are performed:
    • Appends a double quotation mark (") to the sb StringBuilder.
    • Encodes the fname parameter using a JSON encoding algorithm and appends it to the sb StringBuilder.
    • Appends a colon (:) to the sb StringBuilder.
    • Appends the json parameter to the sb StringBuilder.
    • Appends a comma (,) to the sb StringBuilder.
  3. If the json parameter does not meet the conditions from step 1, no action is taken.

Once the addRawJson method has finished execution, the provided StringBuilder will contain the added raw JSON data in the specified format.

The addRawJson method defined in the JsonUtils class in the io.nats.client.support package is responsible for adding raw JSON data to a StringBuilder object.

The method takes three parameters: sb (the StringBuilder object to append the JSON data to), fname (the name of the field/key in the JSON object), and json (the raw JSON data as a string).

The method first checks if the json parameter is not null and has a length greater than 0. If this condition is true, it adds the field/key name (fname) and the colon character (:) to the sb StringBuilder object. Then, it appends the raw JSON data (json) to the sb object, followed by a comma character (,). This allows for the creation of a properly formatted JSON object.

The purpose of this method is to facilitate the building of JSON messages or payloads by allowing the addition of raw JSON data to a StringBuilder object, which can then be used to construct a complete JSON message.

sequence diagram

public static void addField(StringBuilder sb, String fname, String value)

public static void addField(StringBuilder sb, String fname, String value) {
    if (value != null && value.length() > 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLONQ);
        jsonEncode(sb, value);
        sb.append(QCOMMA);
    }
}

addField method Description

The addField method is defined in the JsonUtils class in the io.nats.client.support package. It takes in three parameters: sb of type StringBuilder, fname of type String, and value of type String.

This method is responsible for adding a field to a JSON string representation in a step-by-step manner.

Here is a breakdown of the steps performed by this method:

  1. Check if the value parameter is not null and its length is greater than 0:

    • If the condition is not met, the method exits without performing any further steps.
  2. If the condition is met, the method performs the following steps:

    • Append an opening quote to the StringBuilder (sb) using the append method: sb.append(Q).
    • Call the jsonEncode method, passing sb and fname as arguments to encode the field name as JSON. This method encodes special characters and escapes them if necessary.
    • Append a colon and a trailing quote to sb using the append method: sb.append(QCOLONQ).
    • Call the jsonEncode method, passing sb and value as arguments to encode the field value as JSON.
    • Append a comma to sb using the append method: sb.append(QCOMMA).

This method assumes that the jsonEncode method is available and properly implemented.

The addField method in class JsonUtils is used to add a field to a JSON string.

It takes in a StringBuilder object (sb), the name of the field (fname), and the value of the field (value) as parameters.

The method checks if the value is not null and has a length greater than 0. If it meets this condition, it encodes the field name and value as JSON strings and appends them to the StringBuilder object with specific JSON formatting.

sequence diagram

public static void addFieldEvenEmpty(StringBuilder sb, String fname, String value)

public static void addFieldEvenEmpty(StringBuilder sb, String fname, String value) {
    if (value == null) {
        value = "";
    }
    sb.append(Q);
    jsonEncode(sb, fname);
    sb.append(QCOLONQ);
    jsonEncode(sb, value);
    sb.append(QCOMMA);
}

The addFieldEvenEmpty method in the JsonUtils class is used to add a field to a JSON object represented as a StringBuilder. The method takes three parameters: sb, fname, and value.

Here is a step-by-step description of what the method does:

  1. Check if the value parameter is null.
  2. If the value is null, assign an empty string ("") to the value variable.
  3. Append a double quote (") to the StringBuilder (sb) to denote the beginning of the field.
  4. Encode the fname using the jsonEncode method and append it to the StringBuilder (sb).
  5. Append a colon (:) and a double quote (") to the StringBuilder (sb) to separate the field name and value.
  6. Encode the value using the jsonEncode method and append it to the StringBuilder (sb).
  7. Append a comma (,) to the StringBuilder (sb) to separate multiple fields in a JSON object.

The addFieldEvenEmpty method is a static method defined in the JsonUtils class.

This method takes in three parameters: StringBuilder sb, String fname, and String value.

The purpose of this method is to add a key-value pair field to a JSON string, even if the value is empty or null.

Here's a breakdown of what the method does:

  1. It first checks if the value parameter is null. If it is, it sets the value to an empty string.
  2. It then appends a double quotation mark (") to the StringBuilder sb object.
  3. It encodes the fname parameter using the jsonEncode method and appends it to the sb.
  4. It appends a colon (:) and another double quotation mark to the sb.
  5. It encodes the value parameter using the jsonEncode method and appends it to the sb.
  6. Finally, it appends a comma (,) to the sb to separate multiple key-value pairs in the JSON string.

Overall, the method ensures that even if the value is empty or null, the key-value pair will still be added to the JSON string.

sequence diagram

public static void addField(StringBuilder sb, String fname, Boolean value)

public static void addField(StringBuilder sb, String fname, Boolean value) {
    if (value != null) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value ? "true" : "false").append(COMMA);
    }
}

The addField method in the class io.nats.client.support.JsonUtils is used to add a Boolean field to a JSON object represented by a StringBuilder object.

Here is a step-by-step description of how the addField method works:

  1. Accepts three parameters: sb, fname, and value.

    • sb is a StringBuilder object representing the JSON object.
    • fname is a String representing the name of the field to be added.
    • value is a Boolean representing the value of the field to be added.
  2. Checks if the value is not null.

    • If the value is null, nothing will be done. The method will return without modifying the JSON.
  3. If the value is not null, the following steps are performed:

    • Appends a quotation mark (") to the sb to start the field definition.
    • Encodes the fname using the jsonEncode method and appends it to the sb.
    • Appends a colon (:) to separate the field name and its value.
    • Appends the string representation of the value to the sb based on whether it is true or false.
    • Appends a comma (,) to the sb to indicate that there are more fields to be added.
  4. The method execution ends, and the modified sb can be used to represent the updated JSON object.

Note that the method assumes that the jsonEncode and constants (Q, QCOLON, and COMMA) are defined elsewhere in the class or imported from another package. The specific implementations of these dependencies are not mentioned in the given code snippet.

The addField method in JsonUtils class allows you to add a new field with a Boolean value to a JSON string.

The method takes three parameters:

  1. sb - a StringBuilder object representing the JSON string to which the field will be added.
  2. fname - a String indicating the name of the field.
  3. value - a Boolean value that will be assigned to the field.

Inside the method, it first checks if the value parameter is not null. If the value is not null, it appends the field to the sb string. The field is enclosed in quotes ("), the field name is encoded using the jsonEncode method, followed by a colon (:), and then the boolean value ("true" or "false") is appended. Finally, a comma (,) is added to separate this field from other fields in the JSON string.

sequence diagram

public static void addField(StringBuilder sb, String fname, Integer value)

public static void addField(StringBuilder sb, String fname, Integer value) {
    if (value != null && value >= 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value).append(COMMA);
    }
}

Method: addField(StringBuilder sb, String fname, Integer value)

This method is defined in the io.nats.client.support.JsonUtils class and is used to add a field to a StringBuilder object based on the provided fname (field name) and value parameters.

Parameters:

  • sb (StringBuilder): The StringBuilder object to which the field is added.
  • fname (String): The name of the field to be added.
  • value (Integer): The value of the field to be added.

Steps:

  1. Check if the value parameter is not null and greater than or equal to 0.
  2. If the condition is satisfied, perform the following sub-steps:
    • Append the double quotation mark (") to the sb (StringBuilder) object.
    • Perform JSON encoding of the fname using the jsonEncode method and append the result to the sb object.
    • Append the colon (:) character to the sb object.
    • Append the value parameter to the sb object.
    • Append a comma (,) to the sb object.
  3. Continue with the execution of the remaining code.

The addField method in the JsonUtils class is a static method that adds a field to a StringBuilder object in JSON format. The method takes three parameters - a StringBuilder object sb, a String fname for the field name, and an Integer value for the field value.

The method first checks if the value is not null and if it is greater than or equal to zero. If both conditions are true, the method appends the field name in double quotes (using the jsonEncode method), followed by a colon, the value, and a comma to separate it from other fields in the JSON object.

sequence diagram

public static void addFieldWhenGtZero(StringBuilder sb, String fname, Integer value)

public static void addFieldWhenGtZero(StringBuilder sb, String fname, Integer value) {
    if (value != null && value > 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value).append(COMMA);
    }
}

Method: addFieldWhenGtZero

Class: io.nats.client.support.JsonUtils

This method is used to add a field to a StringBuilder object if the given value is not null and greater than zero.

Parameters:

  • sb: StringBuilder - the StringBuilder object to which the field is appended.
  • fname: String - the name of the field.
  • value: Integer - the value of the field.

Steps:

  1. Check if the value is not null and greater than zero.
  2. If the above condition is true, perform the following steps:
    • Append a quotation mark (") to the StringBuilder object.
    • Encode the field name using the jsonEncode method and append it to the StringBuilder object.
    • Append ":value," to the StringBuilder object, where value is the value of the field.

The addFieldWhenGtZero method in the JsonUtils class is a utility method used for adding a field to a JSON string if the provided value is greater than zero. It takes three parameters: a StringBuilder object sb, a String fname representing the field name, and an Integer value representing the field value.

Inside the method, it checks if the value is not null and greater than zero. If both conditions are true, it appends the field name, encoded in JSON format, followed by a colon and the value to the sb. The field is then separated from other fields by a comma.

This method helps in constructing a JSON string by adding a field only when its value is greater than zero.

sequence diagram

public static void addField(StringBuilder sb, String fname, Long value)

public static void addField(StringBuilder sb, String fname, Long value) {
    if (value != null && value >= 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value).append(COMMA);
    }
}

Method: addField

Description

The addField method is a static method defined in the class io.nats.client.support.JsonUtils. It is used to add a field to a JSON string representation in a step-by-step manner.

Signature

public static void addField(StringBuilder sb, String fname, Long value)

Parameters

  • sb (StringBuilder): The StringBuilder object representing the JSON string.
  • fname (String): The name of the field to be added.
  • value (Long): The value of the field to be added.

Steps

  1. Check if the value is not null and is greater than or equal to 0.
  2. If the condition is true, perform the following sub-steps: a. Append a quotation mark (") to the StringBuilder (sb) to start the field. b. Perform JSON encode on the field name (fname) using the jsonEncode method and append it to the StringBuilder (sb). c. Append a colon (:) to the StringBuilder (sb). d. Append the value (value) to the StringBuilder (sb). e. Append a comma (,) to the StringBuilder (sb).

Note: The Q, QCOLON, and COMMA constants are not provided in the code snippet, but they are assumed to represent the respective characters: ", :, and ,.

The addField method in the io.nats.client.support.JsonUtils class is used to add a field to a JSON formatted string. The method takes three parameters: a StringBuilder object sb, a String parameter fname representing the name of the field, and a Long parameter value representing the value of the field.

The method first checks if the value is not null and greater than or equal to 0. If this condition is true, the method appends the field name in JSON format to the StringBuilder using the jsonEncode method, and then appends the colon symbol and the value to the StringBuilder. Finally, it adds a comma at the end to separate this field from the next field, if any.

sequence diagram

public static void addFieldWhenGtZero(StringBuilder sb, String fname, Long value)

public static void addFieldWhenGtZero(StringBuilder sb, String fname, Long value) {
    if (value != null && value > 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value).append(COMMA);
    }
}

Method Description: addFieldWhenGtZero()

This method is defined in the class io.nats.client.support.JsonUtils and is used to add a field to a StringBuilder object when the value of the field is greater than zero.

Method Signature:

public static void addFieldWhenGtZero(StringBuilder sb, String fname, Long value)

Parameters:

  • sb (StringBuilder): A StringBuilder object to which the field will be added.
  • fname (String): The name of the field being added.
  • value (Long): The value of the field being added.

Method Implementation:

  1. Check if the value is not null and is greater than zero.
  2. If the above condition is true, perform the following steps:
    • Append a quotation mark (") to the StringBuilder object sb.
    • Encode the field name (fname) using the jsonEncode() method and append it to sb.
    • Append a colon (:) character, followed by the value of the field (value), and a comma (,).
  3. If the above condition is false, do nothing.

Note: The method assumes the existence of a jsonEncode() method which is not defined in the provided information.

Example Usage:

StringBuilder sb = new StringBuilder();
String fname = "count";
Long value = 10L;

addFieldWhenGtZero(sb, fname, value);

// The StringBuilder object sb would contain the following:
// "count":10,

The addFieldWhenGtZero method in the JsonUtils class is a utility method that adds a field to a JSON string if the given value is greater than zero.

The method takes in a StringBuilder object sb, which represents the JSON string being built, a String object fname, which represents the name of the field being added, and a Long object value, which represents the value of the field.

The method checks if the value is not null and is greater than zero. If this condition is true, the method encodes the fname as a JSON string, appends it to the sb with a colon and the value, and adds a comma to separate it from other fields.

This method is useful when constructing a JSON object where certain fields should only be included if their values meet a certain condition, specifically if they are greater than zero in this case.

sequence diagram

public static void addFieldWhenGteMinusOne(StringBuilder sb, String fname, Long value)

public static void addFieldWhenGteMinusOne(StringBuilder sb, String fname, Long value) {
    if (value != null && value >= -1) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value).append(COMMA);
    }
}

The addFieldWhenGteMinusOne method in the JsonUtils class is used to add a field (in JSON format) to a StringBuilder object if the provided value is not null and is greater than or equal to -1.

Here is a step-by-step description of how this method works:

  1. Check if the value parameter is not null and is greater than or equal to -1.

    • If the condition is false, the method will simply return without making any changes.
  2. If the condition is true, the method continues to add the field to the StringBuilder object:

    • The JSON key fname is appended to the StringBuilder object, passed as the sb parameter.
    • The key is enclosed within double quotes by first appending Q (which represents the double quote character) to the StringBuilder object, and then invoking the jsonEncode method to encode the fname value and append it to the StringBuilder. This ensures that the key is properly formatted for JSON.
    • A colon character (:) is appended to the StringBuilder object using QCOLON.
    • The value parameter is appended to the StringBuilder object.
    • Finally, a comma character (,) is appended to the StringBuilder object, which allows for adding multiple fields within the same JSON object.

Please note that the variables Q, QCOLON, and COMMA are assumed to be predefined constants representing the respective characters. The jsonEncode method is not provided in the code snippet, but it is expected to handle the encoding of the fname value to ensure it is properly escaped for JSON.

The addFieldWhenGteMinusOne method in JsonUtils class is used to add a field to a StringBuilder object if the provided value is not null and greater than or equal to -1.

The method checks if the value is valid and appends the field name, the value itself, and a comma to the StringBuilder object in a JSON format. The field name is JSON-encoded using the jsonEncode method.

sequence diagram

public static void addFieldAsNanos(StringBuilder sb, String fname, Duration value)

public static void addFieldAsNanos(StringBuilder sb, String fname, Duration value) {
    if (value != null && value != Duration.ZERO) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value.toNanos()).append(COMMA);
    }
}

The addFieldAsNanos method in the JsonUtils class is used to add a field with a Duration value in nanoseconds to a StringBuilder object, based on the provided parameters.

Here is a step-by-step description of what the method does:

  1. Check if the value is not null and not equal to Duration.ZERO.

    • if (value != null && value != Duration.ZERO)
  2. If the above condition is true, then continue with the following steps.

    • This check is used to ignore the null or zero duration values and prevent adding unnecessary fields to the StringBuilder.
  3. Append the opening quotation mark to the StringBuilder.

    • sb.append(Q)
  4. Encode the fname (field name) using the jsonEncode method and append it to the StringBuilder.

    • jsonEncode(sb, fname)
  5. Append the closing quotation mark and a colon to the StringBuilder.

    • sb.append(QCOLON)
  6. Append the value of the Duration object converted to nanoseconds to the StringBuilder.

    • sb.append(value.toNanos())
  7. Append a comma to the end of the field and its value in the StringBuilder.

    • sb.append(COMMA)

The resulting StringBuilder object will contain the appended field and value in the format:

"fname":valueInNanoseconds,

Note: The variables Q, QCOLON, and COMMA are assumed to be constants representing the quotation mark, colon, and comma characters respectively.

The addFieldAsNanos method in the JsonUtils class is used to add a field to a StringBuilder object in the format of key-value pair, where the value is a Duration object represented in nanoseconds.

If the value parameter is not null and not equal to Duration.ZERO, then the method encodes the field name (fname) and appends it to the StringBuilder using JSON encoding. It then appends the value of the Duration object converted to nanoseconds, followed by a comma.

sequence diagram

public static void addField(StringBuilder sb, String fname, JsonSerializable value)

public static void addField(StringBuilder sb, String fname, JsonSerializable value) {
    if (value != null) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLON).append(value.toJson()).append(COMMA);
    }
}

The addField method in the JsonUtils class is used to add a field to a StringBuilder object based on the provided parameters. Here is a step-by-step description of how the method works:

  1. The method takes three parameters:

    • sb, which is a StringBuilder object representing the string to which the field will be added.
    • fname, which is a String representing the name of the field.
    • value, which is a JsonSerializable object representing the value of the field.
  2. The method first checks if the value parameter is not null using the if statement.

  3. If the value is not null, the method proceeds to the next steps. Otherwise, it does nothing.

  4. The method appends a double quotation mark (") to the sb StringBuilder object using the append method.

  5. The method then encodes the fname parameter as a JSON string using the jsonEncode method, and appends it to the sb StringBuilder object using the append method.

  6. The method appends a colon (:) character to the sb StringBuilder object using the append method.

  7. The method converts the value parameter to its JSON representation by calling the toJson method on the value object. The resulting JSON string is then appended to the sb StringBuilder object using the append method.

  8. Finally, the method appends a comma (,) character to the sb StringBuilder object using the append method.

Note: The method does not perform any error checking or exception handling. It assumes that the provided parameters are valid and do not cause any issues during the method execution.

The addField method in the io.nats.client.support.JsonUtils class is used to add a new field to a JSON string.

The method takes three parameters:

  1. sb (StringBuilder): The StringBuilder object used to build the JSON string.
  2. fname (String): The name of the field to be added.
  3. value (JsonSerializable): The value of the field.

The method first checks if the value parameter is not null. If it is not null, the method proceeds to add the field to the JSON string.

The field is added in the following format: "fname":value.toJson(),.

fname is the name of the field, value.toJson() is the serialized representation of the value, and , is the comma used to separate multiple fields in the JSON string.

Note that the method uses the jsonEncode method to encode the field name before appending it to the StringBuilder object.

sequence diagram

public static void _addList(StringBuilder sb, String fname, List list, ListAdder adder)

public static <T> void _addList(StringBuilder sb, String fname, List<T> list, ListAdder<T> adder) {
    sb.append(Q);
    jsonEncode(sb, fname);
    sb.append("\":[");
    for (int i = 0; i < list.size(); i++) {
        if (i > 0) {
            sb.append(COMMA);
        }
        adder.append(sb, list.get(i));
    }
    sb.append("],");
}
```### private static void _addStrings(StringBuilder sb, String fname, List<String> strings) 
```java
private static void _addStrings(StringBuilder sb, String fname, List<String> strings) {
    _addList(sb, fname, strings, (sbs, s) -> {
        sb.append(Q);
        jsonEncode(sb, s);
        sb.append(Q);
    });
}

The method _addStrings in class io.nats.client.support.JsonUtils is used to add a list of strings to a StringBuilder with JSON encoding.

Here is a step-by-step description of what the method does based on its body:

  1. Define the method _addStrings as private and static.
  2. Pass a StringBuilder (sb), a field name (fname), and a list of strings (strings) as arguments to the method.
  3. Call the _addList method, passing sb, fname, and strings as arguments to it. The _addList method is another method in the class.
  4. In the _addList method, a lambda expression is used to define a function for encoding each string in the list. The lambda takes two arguments: a StringBuilder (sbs) and a string (s).
  5. Inside the lambda, append the character Q (which is likely a constant or variable representing a quote character) to the StringBuilder sb.
  6. Call the jsonEncode method, passing sb and the string s as arguments to it. The jsonEncode method likely encodes the string using some JSON encoding rules.
  7. Append the character Q to the StringBuilder sb again, completing the encoding of the string.
  8. The _addList method takes care of adding the encoded strings to sb in a list format.
  9. Once the _addList method returns, the _addStrings method is complete and returns.

The _addStrings method is a private static method defined in the io.nats.client.support.JsonUtils class. It takes three parameters: a StringBuilder object (sb), a string (fname), and a list of strings (strings).

The purpose of this method is to add a list of strings as a JSON array to the StringBuilder object. It achieves this by using the _addList method (not shown in the provided code snippet) to iterate through each string in the strings list.

For each string, the method appends a double quotation mark (") to the StringBuilder (sb), then encodes the string using the jsonEncode method (not shown in the provided code snippet), and finally appends another double quotation mark (") to the StringBuilder.

Overall, the _addStrings method is responsible for adding a list of strings as a JSON array to a StringBuilder object by properly formatting each string within double quotation marks.

sequence diagram

public static void addField(StringBuilder sb, String fname, ZonedDateTime zonedDateTime)

public static void addField(StringBuilder sb, String fname, ZonedDateTime zonedDateTime) {
    if (zonedDateTime != null && !DEFAULT_TIME.equals(zonedDateTime)) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append(QCOLONQ).append(DateTimeUtils.toRfc3339(zonedDateTime)).append(QCOMMA);
    }
}

Method: addField

The addField method is defined in the io.nats.client.support.JsonUtils class. It takes three parameters: sb of type StringBuilder, fname of type String, and zonedDateTime of type ZonedDateTime. The method is used to add a field to the JSON object represented by the StringBuilder sb.

Step 1:

First, the method checks if the zonedDateTime parameter is not null and is not equal to DEFAULT_TIME.

Step 2:

If the condition in Step 1 is true, the method proceeds to add the field to the JSON object.

Step 3:

The method appends a double quote (") character to the sb StringBuilder.

Step 4:

The jsonEncode method is called to encode the fname parameter and append the encoded value to the sb StringBuilder.

Step 5:

The method appends a double quote (") character, a colon (:) character, and another double quote (") character to the sb StringBuilder.

Step 6:

The DateTimeUtils.toRfc3339 method is called to convert the zonedDateTime parameter to the RFC 3339 format. The resulting string is appended to the sb StringBuilder.

Step 7:

The method appends a double quote (") character, a comma (,), and a newline character to the sb StringBuilder.

Step 8:

The addField method is complete. The updated sb StringBuilder now contains the JSON object with the new field added.

The addField method in the JsonUtils class is used to add a field to a JSON string. It takes in a StringBuilder object sb, a field name fname, and a ZonedDateTime object zonedDateTime. If the zonedDateTime is not null and is not equal to the default time, it encodes the field name and appends it, along with the serialized representation of the zonedDateTime in RFC 3339 format, to the StringBuilder sb followed by a comma.

sequence diagram

public static void addField(StringBuilder sb, String fname, Headers headers)

public static void addField(StringBuilder sb, String fname, Headers headers) {
    if (headers != null && headers.size() > 0) {
        sb.append(Q);
        jsonEncode(sb, fname);
        sb.append("\":{");
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            addStrings(sb, entry.getKey(), entry.getValue());
        }
        endJson(sb);
        sb.append(",");
    }
}
```### // ----------------------------------------------------------------------------------------------------
// PRINT UTILS
// ----------------------------------------------------------------------------------------------------
@Deprecated
public static String normalize(String s) 
```java
// ----------------------------------------------------------------------------------------------------
// PRINT UTILS
// ----------------------------------------------------------------------------------------------------
@Deprecated
public static String normalize(String s) {
    return Character.toString(s.charAt(0)).toUpperCase() + s.substring(1).toLowerCase();
}

normalize method in class io.nats.client.support.JsonUtils

The normalize method is a static method in the JsonUtils class. It is used to normalize a given string based on the following steps:

  1. Convert the first character of the input string to uppercase.
  2. Convert all subsequent characters in the input string to lowercase.

Method Signature

public static String normalize(String s)

Parameters

  • s - The string to be normalized.

Return Value

  • The normalized string.

Steps

  1. Convert the first character of the input string to uppercase using the toUpperCase method of the Character class. This can be achieved by calling Character.toString(s.charAt(0)).toUpperCase().
  2. Convert all subsequent characters in the input string to lowercase using the toLowerCase method of the String class. This can be achieved by calling s.substring(1).toLowerCase().
  3. Concatenate the uppercase first character and the lowercase subsequent characters using the + operator.
  4. Return the normalized string.

Deprecated

  • Note: This method is marked as @Deprecated, indicating that it is no longer recommended to be used. Consider using an alternative method or approach.

Example Usage

String input = "hELlo";
String normalized = JsonUtils.normalize(input);
System.out.println(normalized); // Output: Hello

The normalize method, defined in the JsonUtils class in the io.nats.client.support package, is used to normalize a given string. The method takes a single argument, s, which is a string.

The method begins by retrieving the first character of the string using the charAt method. It then converts this character to uppercase using the toUpperCase method.

Next, the method extracts a substring from the original string starting from the second character using the substring method. This substring is then converted to lowercase using the toLowerCase method.

Finally, the method concatenates the uppercase first character with the lowercase substring and returns the resulting normalized string.

Note: This method has been marked as deprecated, which means it is no longer recommended to be used in new code.

sequence diagram

@Deprecated

public static String objectString(String name, Object o)

@Deprecated
public static String objectString(String name, Object o) {
    if (o == null) {
        return name + "=null";
    }
    return o.toString();
}

Method Description: objectString

This method is defined in the class io.nats.client.support.JsonUtils. It is a deprecated method that is used to convert an object into a string representation.

Method Signature:

@Deprecated
public static String objectString(String name, Object o)

Parameters:

  • name (type: String): The name of the object.
  • o (type: Object): The object to be converted into a string representation.

Return Value:

  • The method returns a string representation of the object.

Method Body:

if (o == null) {
    return name + "=null";
}
return o.toString();

The method first checks if the object o is null. If it is, it returns a string in the format "name=null", where name is the name of the object passed to the method.

If the object is not null, it calls the toString() method on the object and returns the resulting string representation.

Deprecated:

This method is marked as @Deprecated, which means it is no longer recommended for use and may be removed in future versions. It is advised to use an alternative method or approach.

The objectString method, defined in the JsonUtils class in the io.nats.client.support package, takes in a name and an object as parameters. It returns a string representation of the object.

If the object is null, the method returns a string in the format name=null. Otherwise, it returns the result of calling the toString() method on the object.

Please note that this method is deprecated, which means it should not be used in new code and may be removed in future versions.

sequence diagram

// ----------------------------------------------------------------------------------------------------

// SAFE NUMBER PARSING HELPERS // ---------------------------------------------------------------------------------------------------- public static Long safeParseLong(String s)

// ----------------------------------------------------------------------------------------------------
// SAFE NUMBER PARSING HELPERS
// ----------------------------------------------------------------------------------------------------
public static Long safeParseLong(String s) {
    try {
        return Long.parseLong(s);
    } catch (Exception e1) {
        try {
            return Long.parseUnsignedLong(s);
        } catch (Exception e2) {
            return null;
        }
    }
}

Step-by-step description of the safeParseLong method:

  1. The method takes a String s as input.

  2. First, it tries to parse the input s as a Long using Long.parseLong(s).

  3. If the parsing is successful and no exception is thrown, the method returns the parsed Long value.

  4. If an exception occurs while parsing the input s as a Long, the method catches the exception and moves to the next step.

  5. In the catch block, the method tries to parse the input s as an unsigned Long using Long.parseUnsignedLong(s).

  6. If the parsing is successful and no exception is thrown, the method returns the parsed unsigned Long value.

  7. If an exception occurs while parsing the input s as an unsigned Long, the method catches the exception and moves to the next step.

  8. In the second catch block, the method returns null, indicating that the input s cannot be parsed as either a Long or an unsigned Long.

This method is designed to handle safe parsing of strings into Long values, providing fallbacks if the first parsing attempt fails.

The safeParseLong method is a helper method defined in the io.nats.client.support.JsonUtils class. It is used to safely parse a string into a Long value without throwing an exception.

The method first attempts to parse the string using the Long.parseLong() method. If this throws an exception, indicating that the string cannot be parsed as a signed long value, the method then tries to parse the string using the Long.parseUnsignedLong() method. If this also throws an exception, the method returns null, indicating that the string could not be parsed as a long value.

This method is particularly useful when dealing with JSON data, where numeric values are often represented as strings. By using the safeParseLong method, software engineers can avoid potential exceptions and handle parsing errors more gracefully.

sequence diagram

@Deprecated

public static String removeObject(String json, String objectName)

@Deprecated
public static String removeObject(String json, String objectName) {
    int[] indexes = getBracketIndexes(objectName, json, '{', '}', 0);
    if (indexes != null) {
        // remove the entire object replacing it with a dummy field b/c getBracketIndexes doesn't consider
        // if there is or isn't another object after it, so I don't have to worry about it being/not being the last object
        json = json.substring(0, indexes[0]) + "\"rmvd" + objectName.hashCode() + "\":\"\"" + json.substring(indexes[1] + 1);
    }
    return json;
}
```### private static List<String> toList(String arrayString) 
```java
private static List<String> toList(String arrayString) {
    List<String> list = new ArrayList<>();
    String[] raw = arrayString.split(",");
    for (String s : raw) {
        String cleaned = s.trim().replace("\"", "");
        if (cleaned.length() > 0) {
            list.add(jsonDecode(cleaned));
        }
    }
    return list;
}
```### @Deprecated
public static String readStringMayHaveQuotes(String json, String field, String dflt) 
```java
@Deprecated
public static String readStringMayHaveQuotes(String json, String field, String dflt) {
    String jfield = "\"" + field + "\"";
    int at = json.indexOf(jfield);
    if (at != -1) {
        at = json.indexOf('"', at + jfield.length());
        StringBuilder sb = new StringBuilder();
        while (true) {
            char c = json.charAt(++at);
            if (c == '\\') {
                char c2 = json.charAt(++at);
                if (c2 == '"') {
                    sb.append('"');
                } else {
                    sb.append(c);
                    sb.append(c2);
                }
            } else if (c == '"') {
                break;
            } else {
                sb.append(c);
            }
        }
        return jsonDecode(sb.toString());
    }
    return dflt;
}
```### @Deprecated
public static byte[] readBase64(String json, Pattern pattern) 
```java
@Deprecated
public static byte[] readBase64(String json, Pattern pattern) {
    Matcher m = pattern.matcher(json);
    String b64 = m.find() ? m.group(1) : null;
    return b64 == null ? null : Base64.getDecoder().decode(b64);
}

Method: readBase64

The readBase64 method is defined in the io.nats.client.support.JsonUtils class. It is used to decode a Base64 encoded string from a JSON string using a provided pattern.

Parameters

  • json (String): The JSON string from which to extract the Base64 encoded string.
  • pattern (Pattern): A regular expression pattern used to match the Base64 encoded string within the JSON.

Return Value

  • If a match is found, the method returns the decoded byte array.
  • If no match is found, the method returns null.

Deprecated

This method is marked as deprecated, indicating that it is no longer recommended to use. It is recommended to check for an alternative method or approach for achieving the desired functionality.

Method Workflow

  1. The method starts by creating a Matcher object using the provided pattern and the input JSON string.
  2. It then attempts to find a match within the JSON string using the Matcher's find method.
  3. If a match is found, the method extracts the matched substring (Base64 encoded string) using the Matcher's group method with a group index of 1.
  4. If no match is found (or if the extracted Base64 encoded string is null), the method returns null.
  5. If a Base64 encoded string is extracted, the method uses the Base64.getDecoder().decode method to decode the string into a byte array.
  6. The decoded byte array is then returned by the method.

Note

The deprecation of this method suggests that there might be a better or more efficient way to achieve the same result. It is recommended to consult the documentation or seek further guidance to determine the replacement or alternative method for the deprecated functionality.

The readBase64 method in the JsonUtils class is used to read and decode a Base64 string from a JSON string. It takes two parameters: json - the JSON string, and pattern - a regex pattern used to extract the Base64 string from the JSON.

First, it uses the provided regex pattern to find a match in the JSON string. If a match is found, the Base64 string is extracted from the captured group. Then, it checks if the extracted Base64 string is null. If it is null, indicating no match was found, the method returns null. Otherwise, the method uses the Base64.getDecoder() method to decode the Base64 string into a byte array, which it returns.

The @Deprecated annotation indicates that this method is no longer recommended to be used and may be removed in future versions.

sequence diagram

@Deprecated

public static Boolean readBoolean(String json, Pattern pattern, Boolean dflt)

@Deprecated
public static Boolean readBoolean(String json, Pattern pattern, Boolean dflt) {
    Matcher m = pattern.matcher(json);
    if (m.find()) {
        return Boolean.parseBoolean(m.group(1));
    }
    return dflt;
}

Method Description - readBoolean

The readBoolean method is a static method defined in the io.nats.client.support.JsonUtils class. It is used to read a boolean value from a JSON string based on a provided pattern.

Method Signature

@Deprecated
public static Boolean readBoolean(String json, Pattern pattern, Boolean dflt)

Parameters

  • json (String): The JSON string from which to read the boolean value.
  • pattern (Pattern): The regular expression pattern used to match the boolean value in the JSON string.
  • dflt (Boolean): The default boolean value returned if no match is found in the JSON string.

Return Value

  • Boolean: The boolean value read from the JSON string, or the default value if no match is found.

Method Implementation

  1. Create a Matcher object by applying the provided pattern to the JSON string.
  2. If the matcher finds a match in the JSON string:
    • Get the matched substring group (group 1).
    • Parse the matched substring as a boolean value using the Boolean.parseBoolean method.
    • Return the parsed boolean value.
  3. If no match is found in the JSON string, return the default boolean value provided.

Note: This method is marked as @Deprecated, so it is recommended to use alternative methods for reading boolean values from JSON.

The readBoolean method in the JsonUtils class, defined in the io.nats.client.support package, is used to read a boolean value from a given JSON string.

The method takes three parameters:

  • json - The JSON string from which the boolean value is to be extracted.
  • pattern - A regular expression pattern that defines the format of the boolean value in the JSON string.
  • dflt - A default boolean value to be returned if the pattern is not matched in the JSON string.

The method uses the Pattern class to create a matcher object and applies it to the JSON string. If the pattern is found in the JSON string, then the method extracts the boolean value and returns it. If the pattern is not found, the method returns the default value.

Note that this method is marked as @Deprecated, which means it is no longer recommended for use and may be removed in future versions.

sequence diagram

@Deprecated

public static void readInt(String json, Pattern pattern, IntConsumer c)

@Deprecated
public static void readInt(String json, Pattern pattern, IntConsumer c) {
    Matcher m = pattern.matcher(json);
    if (m.find()) {
        c.accept(Integer.parseInt(m.group(1)));
    }
}

The readInt method in JsonUtils class, defined in the io.nats.client.support package, is used to extract an integer value from a JSON string based on a given regular expression pattern.

Here is a step-by-step description of what the readInt method does:

  1. The method is marked with the @Deprecated annotation, which means that it is considered outdated and should not be used in new code. However, it is still functional and can be used for backward compatibility.
  2. The method takes three parameters:
    • json - a String representing the JSON object from which the integer value needs to be extracted.
    • pattern - a Pattern object representing the regular expression pattern to be matched against the JSON string.
    • c - an IntConsumer functional interface implementation that will consume the extracted integer value.
  3. Inside the method, a Matcher object is created by calling the matcher method on the pattern object, passing the json string as the input to be matched.
  4. The find method is called on the Matcher object to search for the first occurrence of the pattern in the json string. If a match is found, the next steps are executed; otherwise, the method returns without performing any further action.
  5. The group(1) method is called on the Matcher object to extract the matched portion of the json string corresponding to the first capturing group in the pattern. This assumes that the pattern contains a capturing group (i.e., parentheses) around the integer value.
  6. The extracted string is then converted to an integer using the parseInt method of the Integer class.
  7. Finally, the extracted integer value is passed to the accept method of the IntConsumer functional interface implementation c. This allows the consumer to perform any necessary actions with the extracted value.

Note: The method does not return any result, as the extracted integer value is passed to the IntConsumer consumer.

sequence diagram

@Deprecated

public static void readLong(String json, Pattern pattern, LongConsumer c)

@Deprecated
public static void readLong(String json, Pattern pattern, LongConsumer c) {
    Matcher m = pattern.matcher(json);
    if (m.find()) {
        Long l = safeParseLong(m.group(1));
        if (l != null) {
            c.accept(l);
        }
    }
}

Method readLong Description

This method is defined in the class io.nats.client.support.JsonUtils and is used to extract a Long value from a JSON string based on a given pattern. Here is a step-by-step description of what the method does:

  1. Annotation: The method is annotated with @Deprecated, which indicates that it is no longer recommended for use. It is likely that this method has been replaced by a newer or better alternative.

  2. Parameters: The method takes three parameters: json (a string), pattern (a Pattern object), and c (a LongConsumer interface).

  3. Pattern Matching: The method creates a Matcher object by invoking the matcher() method on the pattern object and passing the json string as an argument. The Matcher object is used for pattern matching on the input JSON string.

  4. Pattern Matching Result: The method checks if the Matcher object finds a match in the input JSON string by invoking the find() method. If a match is found, the method proceeds to the next step; otherwise, it exits and does nothing.

  5. Extract Number: If a match is found, the method uses the group() method of the Matcher object to extract the matched substring. In this case, it extracts the substring captured in the first group (specified by the parentheses in the pattern). This substring should represent a numerical value that can be parsed as a Long type.

  6. Parse Long: The method calls the safeParseLong() method (not shown in the provided code) to parse the extracted substring as a Long value. The result is stored in a Long variable l. The safeParseLong() method likely handles cases where the parsing fails and returns null.

  7. Consuming Long: If the parsed Long value l is not null, the method invokes the accept() method of the LongConsumer interface, passing the l as an argument. This allows the caller of the method to consume the extracted Long value.

That's the step-by-step description of the readLong method. It is important to note that the implementation of the safeParseLong() method and the actual usage of the readLong() method in your code may influence the behavior and purpose of this method further.

The readLong method is a deprecated method defined in the JsonUtils class from the io.nats.client.support package.

It takes three parameters:

  1. json - a string representing a JSON object or JSON data
  2. pattern - a regular expression pattern to search for a specific value in the JSON string
  3. c - a LongConsumer functional interface that allows the method to accept and process a Long value

The method uses the provided regular expression pattern to create a Matcher object and applies it to the json string. If a match is found, it extracts the matched value and attempts to parse it into a Long object using the safeParseLong helper method.

If the parsing is successful and a valid Long object is obtained, the method invokes the accept method of the LongConsumer interface with the parsed Long value as the argument. This allows the caller to provide custom logic to handle the extracted Long value.

Note that the method is marked as deprecated, which means it is no longer recommended to be used in new code and may be removed in future versions of the library.

sequence diagram

@Deprecated

public static void readNanos(String json, Pattern pattern, Consumer c)

@Deprecated
public static void readNanos(String json, Pattern pattern, Consumer<Duration> c) {
    Matcher m = pattern.matcher(json);
    if (m.find()) {
        c.accept(Duration.ofNanos(Long.parseLong(m.group(1))));
    }
}

The method readNanos in the class io.nats.client.support.JsonUtils is used to extract a Duration value from a JSON string, using a specified regex pattern. This method performs the following steps:

  1. The method is marked as @Deprecated, indicating that it is no longer recommended to use this method. Users should consider using an alternative method instead.

  2. The method takes three parameters:

    • json (String): The JSON string from which the Duration value needs to be extracted.
    • pattern (Pattern): The regular expression pattern used to match and extract the Duration value from the JSON string.
    • c (Consumer): A consumer function that accepts a Duration object. This function will be called with the extracted Duration value.
  3. Inside the method, it creates a Matcher object by applying the regex pattern to the provided JSON string.

    Matcher m = pattern.matcher(json);
    
  4. It then checks if the Matcher object finds a match in the JSON string.

    if (m.find()) {
      ...
    }
    
  5. If a match is found, it uses the group method of the Matcher object to retrieve the captured group with index 1 (assuming the pattern has at least one capturing group).

    Long.parseLong(m.group(1))
    
  6. It then creates a Duration object by calling the ofNanos method and passing the parsed long value. This Duration object represents the extracted Duration value in nanoseconds.

    Duration.ofNanos(Long.parseLong(m.group(1)))
    
  7. Finally, it calls the accept method of the Consumer object (c) and passes the created Duration object as the argument. This allows users of the method to process the extracted Duration value according to their needs.

    c.accept(Duration.ofNanos(Long.parseLong(m.group(1))));
    

This method facilitates the extraction of a Duration value from a JSON string using a provided regex pattern, and provides a way to consume and process the extracted value using a callback function.

The readNanos method in the io.nats.client.support.JsonUtils class is used to parse a JSON string and extract a duration in nanoseconds based on a given regular expression pattern. The method takes three parameters: json (the JSON string to parse), pattern (the regular expression pattern to match against the JSON string), and c (a consumer function that accepts a Duration object).

The method firstly creates a Matcher object by applying the pattern to the JSON string. If a match is found, the method extracts the matched group (assumed to be a number representing nanoseconds) and parses it into a long value. Finally, the method constructs a Duration object using the parsed value and passes it to the consumer function c for further processing.

Please note that this method is marked as deprecated, suggesting that it may be outdated or should be used with caution. It is recommended to refer to the API documentation or consult the code maintainers for more information on the deprecation and possible alternatives.

sequence diagram

public static boolean listEquals(List l1, List l2)

public static <T> boolean listEquals(List<T> l1, List<T> l2) {
    if (l1 == null) {
        return l2 == null;
    }
    if (l2 == null) {
        return false;
    }
    return l1.equals(l2);
}

Method: listEquals

The listEquals method is defined in the io.nats.client.support.JsonUtils class. It is a public static method that takes two generic List objects, l1 and l2, as parameters. It returns a boolean value indicating whether the two lists are equal.

Step 1: Check if l1 is null

  • If the l1 parameter is null, proceed to step 2.
  • If l1 is null and l2 is also null, return true. This means that if both lists are null, then they are considered equal. Return true and end the method execution.

Step 2: Check if l2 is null

  • If the l1 parameter is not null and the l2 parameter is null, proceed to step 3.
  • If l1 is not null and l2 is null, return false. This means that if one list is null and the other is not, they are not considered equal. Return false and end the method execution.

Step 3: Check if l1 is equal to l2

  • If both l1 and l2 are not null, compare their contents for equality using the equals method of the List class.
  • If the contents of l1 are equal to the contents of l2, return true. This means that if the two lists have the same elements in the same order, they are considered equal.
  • If the contents of l1 are not equal to the contents of l2, return false. This means that if the two lists have different elements or the elements are in a different order, they are not considered equal.

Note: The equals method being used is the one defined by the List interface, which compares the elements of the lists for equality. The behavior of this method may depend on the implementation of the concrete List class being used.

End of method execution.

The method listEquals in the class JsonUtils compares two lists (l1 and l2) to check if they are equal. It follows the following logic:

  • If l1 is null, it returns true if and only if l2 is also null.
  • If l2 is null, it returns false.
  • Otherwise, it uses the equals method to compare the two lists and returns the result.

Overall, this method helps to determine whether two lists are equal by considering both their contents and order.

sequence diagram

public static boolean mapEquals(Map<String, String> map1, Map<String, String> map2)

public static boolean mapEquals(Map<String, String> map1, Map<String, String> map2) {
    if (map1 == null) {
        return map2 == null;
    }
    if (map2 == null || map1.size() != map2.size()) {
        return false;
    }
    for (String key : map1.keySet()) {
        if (!Objects.equals(map1.get(key), map2.get(key))) {
            return false;
        }
    }
    return true;
}

The mapEquals method in the JsonUtils class is used to compare two Map objects of type Map<String, String> and determine if they are equal. Here's a step-by-step description of what the method does:

  1. Check if map1 is null. If it is, return true if and only if map2 is also null.
  2. Check if map2 is null or if the size of map1 is different from the size of map2. If either of these conditions is true, return false.
  3. Iterate over each key in map1 using a for-each loop.
  4. For each key, compare the corresponding values in map1 and map2 using the Objects.equals method. If the values are not equal, return false.
  5. If all key-value pairs in map1 are equal to their corresponding pairs in map2, return true.

In summary, the mapEquals method checks if two Map objects are equal by comparing their keys and values. It returns true if both maps are null, have the same size, and contain the same key-value pairs; otherwise, it returns false.

The mapEquals method in the JsonUtils class is a static method that compares two Map<String, String> objects.

This method checks if either of the maps is null and returns true only if both are null. If only one map is null or if both maps have different sizes, it returns false.

Next, the method iterates over the keys in map1 and checks if the values of each key in map1 and map2 are equal using the Objects.equals method. If any key-value pair is not equal, it returns false.

If all key-value pairs are equal, it returns true, indicating that both maps are equal.

sequence diagram

HttpRequest

HttpRequest

The HttpRequest class encapsulates an HttpRequest. It is used to support older JVMs where the Java 11 java.net.http.HttpRequest class is not available.

public HttpRequest method(String method)

public HttpRequest method(String method) {
    if (null == method) {
        throw new IllegalArgumentException("HttpRequest method must be non-null");
    }
    this.method = method.trim().toUpperCase();
    return this;
}

The method(String method) method in the io.nats.client.support.HttpRequest class is used to set the HTTP request method. Here is a step-by-step description of what this method does based on its body:

  1. Check if the method parameter is null.
  2. If the method is null, throw an IllegalArgumentException with the message "HttpRequest method must be non-null".
  3. Trim the leading and trailing spaces of the method parameter.
  4. Convert the method parameter to uppercase using the toUpperCase() method.
  5. Set the value of the method instance variable in the class to the trimmed and uppercase method parameter.
  6. Return the current instance of the HttpRequest object.

In summary, this method ensures that the HTTP request method is set correctly by checking for null values, trimming leading and trailing spaces, converting the method to uppercase, and setting it as the value of the method instance variable in the class.

The method method in the HttpRequest class is responsible for setting the HTTP method for the request. It takes a String parameter called method, which represents the desired HTTP method (e.g., GET, POST, etc.).

If the method parameter is null, it throws an IllegalArgumentException with the message "HttpRequest method must be non-null".

Otherwise, it trims and converts the method parameter to uppercase and assigns it to the this.method variable. Finally, it returns the modified HttpRequest object.

sequence diagram

public HttpRequest uri(String uri)

public HttpRequest uri(String uri) {
    if (null == uri) {
        throw new IllegalArgumentException("HttpRequest uri must be non-null");
    }
    this.uri = uri;
    return this;
}

The uri method in the HttpRequest class is used to set the URI (Uniform Resource Identifier) for the HTTP request. The URI is a string that identifies a resource on the internet.

Here is a step-by-step description of what this method does based on its BODY:

  1. The method takes a single parameter, uri, which represents the URI for the HTTP request.

  2. It checks if the uri parameter is null. If it is null, an IllegalArgumentException is thrown with the message "HttpRequest uri must be non-null".

  3. If the uri parameter is not null, it assigns the value of uri to the this.uri field of the HttpRequest object.

  4. Finally, it returns the current HttpRequest object. This is done to support method chaining, allowing for a fluent API where multiple method calls can be chained together in a single line.

Overall, this method ensures that a non-null URI is provided for the HTTP request and stores it in the HttpRequest object for later use.

The uri method in the io.nats.client.support.HttpRequest class is used to set the URI of the HTTP request. It takes a string parameter uri and validates that it is not null. If the uri parameter is null, it throws an IllegalArgumentException. The method then sets the uri field of the HttpRequest object and returns the updated object.

sequence diagram

public HttpRequest version(String version)

public HttpRequest version(String version) {
    if (null == version) {
        throw new IllegalArgumentException("HttpRequest version must be non-null");
    }
    this.version = version;
    return this;
}

The version method in the HttpRequest class is used to set the version of the HTTP request. It takes a String parameter version and returns an instance of HttpRequest.

The method has the following steps:

  1. Check if the version parameter is null. If it is null, throw an IllegalArgumentException with the message "HttpRequest version must be non-null".

  2. Set the version field of the HttpRequest instance to the value of the version parameter.

  3. Return the modified HttpRequest instance.

This method is useful when you want to set the version of the HTTP request being made using the HttpRequest class. It ensures that the version is not null and throws an exception if it is, preventing null pointer exceptions or invalid values.

The version method in the io.nats.client.support.HttpRequest class is used to set the version of the HTTP request. It takes a String parameter version and assigns it to the this.version field of the HttpRequest object.

If the version parameter is null, an IllegalArgumentException is thrown to indicate that the HTTP request version must be non-null.

The method then returns the updated HttpRequest object, allowing for method chaining if desired.

sequence diagram

JsonValueUtils

JsonValueUtils

The JsonValueUtils class is an abstract class that provides internal helper methods for dealing with JSON values.

public static Map<String, String> readStringStringMap(JsonValue jv, String key)

public static Map<String, String> readStringStringMap(JsonValue jv, String key) {
    JsonValue o = readObject(jv, key);
    if (o.type == Type.MAP && o.map.size() > 0) {
        Map<String, String> temp = new HashMap<>();
        for (String k : o.map.keySet()) {
            String value = readString(o, k);
            if (value != null) {
                temp.put(k, value);
            }
        }
        return temp.isEmpty() ? null : temp;
    }
    return null;
}

Method Description: readStringStringMap

This method is defined in the class io.nats.client.support.JsonValueUtils. It takes in two parameters: jv of type JsonValue and key of type String. The method returns a Map<String, String>, which is a mapping of string keys to string values.

Method Signature

public static Map<String, String> readStringStringMap(JsonValue jv, String key)

Parameters

  • jv: A JsonValue object that represents the body of the JSON response.
  • key: A String parameter that represents the key to be used for retrieving a specific value from the JSON response.

Method Steps:

  1. Retrieve the object specified by the provided key from the jv JSON response using the readObject method.
  2. Check if the retrieved object o is of type MAP and has a size greater than 0.
  3. If the above condition is true, create a new HashMap object called temp to store the mapping of keys to values.
  4. Iterate over each key in the o.map set:
    • Retrieve the string value associated with the current key using the readString method from the o object.
    • If the retrieved value is not null, add the key-value pair to the temp map using the put method.
  5. Check if the temp map is empty. If it is, return null; otherwise, return the temp map.
  6. If the condition in step 2 is false, return null.

The readStringStringMap method is a static method defined in the class io.nats.client.support.JsonValueUtils.

This method takes in two parameters: JsonValue jv and String key.

The purpose of this method is to read a JSON object (jv) and retrieve a nested JSON map under a specific key (key).

If the nested JSON object exists and is not empty, the method creates a new HashMap<String, String> called temp. It loops through each key in the nested JSON map and retrieves the corresponding value as a string using the readString method.

If the value is not null, it adds the key-value pair to the temp map.

Finally, the method checks if the temp map is empty. If it is, it returns null; otherwise, it returns the temp map.

sequence diagram

public static int readInteger(JsonValue jsonValue, String key, int dflt)

public static int readInteger(JsonValue jsonValue, String key, int dflt) {
    return read(jsonValue, key, v -> {
        if (v != null) {
            Integer i = getInteger(v);
            if (i != null) {
                return i;
            }
        }
        return dflt;
    });
}

The method readInteger is defined in the class io.nats.client.support.JsonValueUtils. It takes three parameters: jsonValue, key, and dflt.

The purpose of this method is to read an integer value from a JsonValue object based on a given key. If the key is not found or the value is not an integer, a default value (dflt) is returned.

Here is a step-by-step description of what the method is doing:

  1. It calls the read method passing the jsonValue, key, and a lambda function as arguments. The lambda function takes a JsonValue parameter v and returns an integer value.

  2. In the lambda function, it checks if the v is not null. If it is not null, it proceeds to the next step.

  3. Inside the if condition, it calls the getInteger method passing the v as an argument. The getInteger method returns an Integer object representing the value of v if it can be converted to an integer, otherwise, it returns null.

  4. If the i (Integer) object is not null (v can be converted to an integer), it returns i (the converted integer).

  5. If the v is null or cannot be converted to an integer, it returns the default value dflt.

sequence diagram

public static long readLong(JsonValue jsonValue, String key, long dflt)

public static long readLong(JsonValue jsonValue, String key, long dflt) {
    return read(jsonValue, key, v -> {
        if (v != null) {
            Long l = getLong(v);
            if (l != null) {
                return l;
            }
        }
        return dflt;
    });
}

The method readLong defined in class io.nats.client.support.JsonValueUtils is used to read a long value from a JsonValue object by specifying a key. Below is a step-by-step description of how the method works:

  1. The method readLong takes three parameters: jsonValue of type JsonValue, key of type String, and dflt of type long.

    • jsonValue is the input JsonValue object from which the value is to be read.
    • key is the key to identify the value within the jsonValue object.
    • dflt is the default value to be returned if the requested key is not found or the value is not a long.
  2. The method utilizes the read method of the same class to perform the actual read operation.

    • The read method takes a JsonValue object, a key, and a callback function as parameters.
    • The callback function is implemented internally and evaluates the value associated with the specified key.
  3. The callback function checks if the value associated with the key is not null:

    • If the value is not null, it tries to convert it to a Long using the getLong method.
    • The getLong method is also implemented internally and attempts to parse the value as a long.
    • If the conversion is successful, the parsed Long value is returned.
    • If the value cannot be parsed as a long, the method returns the default value dflt.
  4. If the value associated with the key is null or cannot be parsed as a long, the method returns the default value dflt.

In summary, the readLong method reads a long value from a JsonValue object by specifying a key. If the specified key is found and the associated value can be parsed as a long, that value is returned. Otherwise, the default value dflt is returned.

The readLong method in the io.nats.client.support.JsonValueUtils class is used to read a long value from a JsonValue object using a specified key.

Here's what the method does:

  1. It takes in three parameters: a JsonValue object, a String key, and a default value (dflt) to be returned if the value is not found or cannot be parsed as a long.

  2. The method calls the read method passing the JsonValue, key, and a lambda expression.

  3. Within the lambda expression, it first checks if the JsonValue is not null and if it can be parsed as a Long type.

  4. If the value is a valid Long, it returns the parsed long value.

  5. If any of the above conditions are not met, it returns the default value specified (dflt).

In summary, the readLong method reads a long value from a JsonValue object using a specified key and returns either the parsed value or a default value if the value is not found or cannot be parsed.

sequence diagram

public static List listOf(JsonValue v, Function<JsonValue, T> provider)

public static <T> List<T> listOf(JsonValue v, Function<JsonValue, T> provider) {
    List<T> list = new ArrayList<>();
    if (v != null && v.array != null) {
        for (JsonValue jv : v.array) {
            T t = provider.apply(jv);
            if (t != null) {
                list.add(t);
            }
        }
    }
    return list;
}

listOf(JsonValue v, Function<JsonValue, T> provider) Method

This method is defined in the class io.nats.client.support.JsonValueUtils and returns a list of objects of type T. The purpose of this method is to extract objects from a JsonValue object and populate a list using a provided function.

Parameters

  • v (type: JsonValue): The input JsonValue object from which objects will be extracted.
  • provider (type: Function<JsonValue, T>): A function that takes a JsonValue object as input and produces an object of type T.

Return Value

  • A list of objects of type T.

Steps

  1. Create an empty ArrayList called list to store the extracted objects.
  2. Check if the input JsonValue object v is not null and its array property is not null.
  3. If the above condition is satisfied, iterate over each JsonValue object jv in the array property of v.
  4. Using the provided function provider, obtain an object of type T by applying it on the current jv.
  5. Check if the obtained object t is not null.
  6. If the above condition is satisfied, add t to the list.
  7. After looping through all the JsonValue objects in the array, return the populated list.

Note: This method is used to efficiently extract objects from a JsonValue array, and skip any null objects in the process. The provided function allows customization on how the JsonValue objects should be transformed into objects of type T.

The listOf method in the JsonValueUtils class is a utility method that takes in a JsonValue object and a Function that converts a JsonValue to a desired type T. It returns a List containing the converted JsonValue objects.

Here is a breakdown of what the method does:

  1. It initializes an empty ArrayList called list.
  2. It checks if the input JsonValue object (v) is not null and if its array attribute is not null.
  3. If both conditions are met, it iterates over each JsonValue (jv) in the array attribute of the input JsonValue object.
  4. It applies the provided provider function to each JsonValue and returns the resulting value of type T.
  5. If the returned value (t) is not null, it adds it to the list.
  6. Finally, it returns the populated list containing the converted JsonValue objects.

This method is useful for converting an array of JsonValue objects into a list of objects of a specific type.

sequence diagram

public static List readStringListIgnoreEmpty(JsonValue jsonValue, String key)

public static List<String> readStringListIgnoreEmpty(JsonValue jsonValue, String key) {
    return read(jsonValue, key, v -> listOf(v, jv -> {
        if (jv.string != null) {
            String s = jv.string.trim();
            if (s.length() > 0) {
                return s;
            }
        }
        return null;
    }));
}

The readStringListIgnoreEmpty method is a public static method defined in the io.nats.client.support.JsonValueUtils class. It takes two parameters: jsonValue of type JsonValue and key of type String. It returns a List<String>.

Here is a step-by-step description of what this method does:

  1. It calls the read method, passing in the jsonValue, key, and a lambda expression as arguments. The lambda expression is responsible for transforming the input value to a list of strings.

  2. Inside the lambda expression, it uses the listOf method to create a list containing the input value (v) and another lambda expression.

  3. The nested lambda expression checks if the input value has a non-null string value.

  4. If the string value is not null, it trims the string and checks if its length is greater than zero.

  5. If the trimmed string has a length greater than zero, it returns the string as a valid value for the list.

  6. If the trimmed string has a length of zero (i.e., it was empty after being trimmed), it returns null.

  7. If the string value is null or the trimmed string has a length of zero, it returns null.

  8. The read method finally returns the list of valid string values, excluding any empty strings.

  9. The readStringListIgnoreEmpty method returns the list of valid string values obtained from the read method.

Note: The provided code snippet is missing the definition of the read and listOf methods, so the exact behavior of those methods is not clear from the given information.

The readStringListIgnoreEmpty method, defined in the io.nats.client.support.JsonValueUtils class, is used to read a list of strings from a JsonValue object, ignoring any empty or whitespace-only strings.

The method takes two parameters: jsonValue, which is the JsonValue object to read from, and key, which is the key to retrieve the list of strings from within the JsonValue.

Inside the method, the read method is called, passing in the jsonValue, key, and a lambda function that specifies how to transform each element of the list.

The lambda function checks if each element is a non-null string and trims it to remove any leading or trailing whitespace. If the resulting string has a length greater than 0, it is returned; otherwise, null is returned.

The read method returns a list of transformed elements, and that list is returned from the readStringListIgnoreEmpty method.

sequence diagram

public static List readNanosList(JsonValue jsonValue, String key, boolean nullIfEmpty)

public static List<Duration> readNanosList(JsonValue jsonValue, String key, boolean nullIfEmpty) {
    List<Duration> list = read(jsonValue, key, v -> listOf(v, vv -> {
        Long l = getLong(vv);
        return l == null ? null : Duration.ofNanos(l);
    }));
    return list.size() == 0 && nullIfEmpty ? null : list;
}

The method readNanosList in the class io.nats.client.support.JsonValueUtils is responsible for reading a list of Duration objects from a JsonValue based on a specified key. The method takes three parameters: jsonValue, key, and nullIfEmpty.

Here is a step-by-step description of what the method does:

  1. The method initializes an empty List<Duration> object called list.
  2. It calls the read method of the JsonValueUtils class, passing in the jsonValue, key, and a lambda expression as parameters.
  3. The lambda expression defines a conversion function that takes a JsonValue parameter v and returns a list of Duration objects. This conversion function is responsible for extracting a Long value from the JsonValue and converting it into a Duration object.
  4. Inside the conversion function, the listOf method is called, passing in the JsonValue parameter v and another lambda expression as parameters.
  5. The nested lambda expression defines a conversion function that takes a JsonValue parameter vv and returns a Duration object. This conversion function extracts a Long value from the JsonValue and checks if it is null. If the Long value is null, the conversion function returns null. Otherwise, it creates a Duration object using the Duration.ofNanos method and returns it.
  6. The read method returns a List<Duration>, which is assigned to the list variable.
  7. The method checks if the size of the list is 0 and nullIfEmpty is true. If both conditions are true, the method returns null. Otherwise, it returns the list.

The readNanosList method is a utility method in the JsonValueUtils class that is used to read a list of Duration values from a JSON object.

The method takes three parameters:

  • jsonValue: The input JSON object from which to read the list.
  • key: The key in the JSON object that corresponds to the list.
  • nullIfEmpty: A boolean flag indicating whether to return null if the list is empty.

Inside the method, it uses another utility method called read to read the list of JsonValue objects from the input JSON object. Then, it performs a conversion on each element of the list using a lambda expression.

The lambda expression checks if the value is a Long, and if so, converts it to a Duration object representing the number of nanoseconds. If the value is not a Long, it returns null.

Finally, the method checks if the resulting list is empty and nullIfEmpty is true, it returns null. Otherwise, it returns the list of Duration objects.

In summary, the readNanosList method reads a list of durations in nanoseconds from a JSON object and returns it as a List<Duration>. If the list is empty and the nullIfEmpty parameter is true, it returns null.

sequence diagram

@SuppressWarnings("rawtypes")

public static JsonValue instance(Collection list)

@SuppressWarnings("rawtypes")
public static JsonValue instance(Collection list) {
    JsonValue v = new JsonValue(new ArrayList<>());
    for (Object o : list) {
        v.array.add(toJsonValue(o));
    }
    return v;
}

The instance method in class io.nats.client.support.JsonValueUtils takes a Collection as a parameter and returns a JsonValue instance. Here is a step-by-step description of what the method does:

  1. Creates a new JsonValue instance:
JsonValue v = new JsonValue(new ArrayList<>());
  • This line creates a new JsonValue object and initializes its array field with an empty ArrayList.
  1. Iterates over the elements in the input Collection:
for (Object o : list) {
    v.array.add(toJsonValue(o));
}
  • This for loop iterates over each element of the list parameter.
  • For each element, the method calls the toJsonValue method, passing in the element as a parameter.
  • The result of toJsonValue is then added to the array field of the JsonValue object.
  • This loop continues until all elements in the list have been processed.
  1. Returns the JsonValue instance:
return v;
  • After the loop completes, the method returns the JsonValue object that was created at the beginning.

Note: The method uses @SuppressWarnings("rawtypes") annotation to suppress warnings related to the use of raw types in the method signature.

The method instance in the JsonValueUtils class is responsible for creating a JsonValue object based on a given collection of elements.

It takes a collection as input and creates a new instance of JsonValue with an empty ArrayList. Then, it iterates through each element in the collection, converts it to a JSON value using the toJsonValue method, and adds it to the array in the JsonValue object.

Finally, the method returns the created JsonValue object.

sequence diagram

@SuppressWarnings("rawtypes")

public static JsonValue instance(Map map)

@SuppressWarnings("rawtypes")
public static JsonValue instance(Map map) {
    JsonValue v = new JsonValue(new HashMap<>());
    for (Object key : map.keySet()) {
        v.map.put(key.toString(), toJsonValue(map.get(key)));
    }
    return v;
}

Method Description: instance

This method is defined in the io.nats.client.support.JsonValueUtils class. It returns a JsonValue object based on the provided Map object.

@SuppressWarnings("rawtypes")
public static JsonValue instance(Map map) {
    JsonValue v = new JsonValue(new HashMap<>());
    for (Object key : map.keySet()) {
        v.map.put(key.toString(), toJsonValue(map.get(key)));
    }
    return v;
}

Step-by-Step Description:

  1. Create a new instance of JsonValue using an empty HashMap object:
    JsonValue v = new JsonValue(new HashMap<>());
  2. Iterate over each key in the provided Map object:
    for (Object key : map.keySet()) {
  3. Convert the value of the current key in the Map to a JsonValue object using the toJsonValue method (not shown in the provided code snippet):
    v.map.put(key.toString(), toJsonValue(map.get(key)));
  4. Add the converted JsonValue object to the map field of the JsonValue instance, using the key from the Map as the key in the map field:
    v.map.put(key.toString(), toJsonValue(map.get(key)));
  5. Repeat steps 3 and 4 for each key-value pair in the Map.
  6. Return the created JsonValue instance:
    return v;

The method instance from the class io.nats.client.support.JsonValueUtils takes a Map as a parameter and returns a JsonValue. It creates a new JsonValue object with an empty HashMap.

It then iterates through each key in the input map. For each key, it retrieves the corresponding value from the map using map.get(key) and converts it into a JsonValue using the toJsonValue method. It then puts the key-value pair into the map of the newly created JsonValue object.

Finally, it returns the JsonValue object with the populated map.

sequence diagram

public static JsonValue toJsonValue(Object o)

public static JsonValue toJsonValue(Object o) {
    if (o == null) {
        return JsonValue.NULL;
    }
    if (o instanceof JsonValue) {
        return (JsonValue) o;
    }
    if (o instanceof JsonSerializable) {
        return ((JsonSerializable) o).toJsonValue();
    }
    if (o instanceof Map) {
        //noinspection unchecked,rawtypes
        return new JsonValue((Map) o);
    }
    if (o instanceof List) {
        //noinspection unchecked,rawtypes
        return new JsonValue((List) o);
    }
    if (o instanceof Set) {
        //noinspection unchecked,rawtypes
        return new JsonValue(new ArrayList<>((Set) o));
    }
    if (o instanceof String) {
        String s = ((String) o).trim();
        return s.length() == 0 ? new JsonValue() : new JsonValue(s);
    }
    if (o instanceof Boolean) {
        return new JsonValue((Boolean) o);
    }
    if (o instanceof Integer) {
        return new JsonValue((Integer) o);
    }
    if (o instanceof Long) {
        return new JsonValue((Long) o);
    }
    if (o instanceof Double) {
        return new JsonValue((Double) o);
    }
    if (o instanceof Float) {
        return new JsonValue((Float) o);
    }
    if (o instanceof BigDecimal) {
        return new JsonValue((BigDecimal) o);
    }
    if (o instanceof BigInteger) {
        return new JsonValue((BigInteger) o);
    }
    return new JsonValue(o.toString());
}

The toJsonValue method in class io.nats.client.support.JsonValueUtils is used to convert an object into a JsonValue object. Here is a step-by-step description of what this method does:

  1. Check if the input object o is null. If it is, return a JsonValue object with value null.
  2. Check if the input object o is already an instance of JsonValue. If it is, cast it to JsonValue and return it.
  3. Check if the input object o is an instance of JsonSerializable. If it is, call the toJsonValue method of the object and return the result.
  4. Check if the input object o is an instance of Map. If it is, create a new JsonValue object using the Map constructor and return it.
  5. Check if the input object o is an instance of List. If it is, create a new JsonValue object using the List constructor and return it.
  6. Check if the input object o is an instance of Set. If it is, create a new ArrayList with the elements of the Set, then create a new JsonValue object using the ArrayList constructor and return it.
  7. Check if the input object o is an instance of String. If it is, trim the string and check if it is empty. If it is empty, create a new empty JsonValue object, otherwise create a new JsonValue object with the trimmed string and return it.
  8. Check if the input object o is an instance of Boolean, Integer, Long, Double, Float, BigDecimal, or BigInteger. If it is, create a new JsonValue object with the value of the object and return it.
  9. If none of the above conditions are met, convert the object to a string using the toString method and create a new JsonValue object with the string and return it.

The toJsonValue method in io.nats.client.support.JsonValueUtils is a static method that converts an object into a JsonValue object.

Here's a breakdown of the logic in the method:

  • If the input object is null, it returns a JsonValue.NULL.
  • If the input object is already an instance of JsonValue, it simply returns the object.
  • If the input object implements the JsonSerializable interface, it calls the toJsonValue() method on that object and returns the result.
  • If the input object is a Map, it creates a new JsonValue object using the constructor that accepts a Map.
  • If the input object is a List, it creates a new JsonValue object using the constructor that accepts a List.
  • If the input object is a Set, it creates a new JsonValue object by converting the Set to an ArrayList and passing it to the JsonValue constructor that accepts a List.
  • If the input object is a String, it trims the string and checks its length. If the length is 0, it returns a new empty JsonValue object; otherwise, it returns a JsonValue object containing the trimmed string.
  • If the input object is a Boolean, Integer, Long, Double, Float, BigDecimal, or BigInteger, it creates a new JsonValue object by passing the object to the corresponding constructor.
  • If none of the above conditions are met, it converts the object to a string and creates a new JsonValue object containing that string.

Overall, the toJsonValue method is responsible for converting various types of objects into their corresponding JsonValue representations.

ByteArrayPrimitiveBuilder

ByteArrayPrimitiveBuilder

The ByteArrayPrimitiveBuilder class extends the BuilderBase class. This class allows for the construction of byte array primitives.

@Override

public byte[] toByteArray()

@Override
public byte[] toByteArray() {
    byte[] bytes = new byte[position];
    System.arraycopy(buffer, 0, bytes, 0, position);
    return bytes;
}

The toByteArray method in the ByteArrayPrimitiveBuilder class is used to convert the buffer used by the builder to a byte array. The method follows the below step-by-step description:

  1. Create a new byte array called bytes with a length equal to the current position of the buffer.
  2. Use the System.arraycopy method to copy the contents of the buffer to the bytes array, starting from index 0 and copying position number of elements.
  3. Return the bytes array, which now contains the contents of the buffer up to the current position.

The toByteArray() method in the ByteArrayPrimitiveBuilder class, located in the io.nats.client.support package, generates a new byte array containing the data stored in the underlying buffer of the builder.

Internally, the method first creates a new byte array called bytes, with a size equal to the current position of the buffer. It then uses the System.arraycopy() method to copy the content of the buffer into the newly created bytes array, starting from index 0 and ending at the current position. Finally, it returns the bytes array containing the copied data.

In summary, this method is responsible for converting the data stored in the builder's buffer into a byte array for further processing or transmission.

sequence diagram

public void ensureCapacity(int bytesNeeded)

public void ensureCapacity(int bytesNeeded) {
    int bytesAvailable = buffer.length - position;
    if (bytesAvailable < bytesNeeded) {
        byte[] newBuffer = new byte[bufferAllocSize(position + bytesNeeded, allocationSize)];
        System.arraycopy(buffer, 0, newBuffer, 0, position);
        buffer = newBuffer;
    }
}

The ensureCapacity method in the ByteArrayPrimitiveBuilder class is responsible for ensuring that the underlying buffer has enough capacity to store the specified number of bytes. Here is a step-by-step description of what the method does:

  1. Calculate the number of bytes available in the current buffer. This is done by subtracting the current position from the length of the buffer. This will give us the number of bytes that can be added to the buffer without exceeding its capacity.

  2. Check if the number of bytes available is less than the number of bytes needed. If this condition is true, it means that the current buffer does not have enough capacity to store the required number of bytes.

  3. If the buffer capacity is insufficient, allocate a new buffer with an increased size. The new buffer size is determined by calling the bufferAllocSize method, passing in the sum of the current position and the number of bytes needed, as well as the allocationSize value. This method calculates the appropriate buffer size based on the given parameters.

  4. Copy the contents of the current buffer to the new buffer. This is done using the System.arraycopy method. The contents are copied from the starting position 0 in the old buffer to the starting position 0 in the new buffer, up to the current position.

  5. Update the reference to the buffer with the new buffer. This ensures that future operations on the ByteArrayPrimitiveBuilder use the increased capacity buffer.

By following these steps, the ensureCapacity method in the ByteArrayPrimitiveBuilder class guarantees that the underlying buffer will have enough capacity to accommodate the specified number of bytes. This is achieved by increasing the buffer size if necessary and copying the existing data to the new buffer.

The ensureCapacity method in the ByteArrayPrimitiveBuilder class is used to check if the existing buffer has enough capacity to accommodate a specified number of bytes. If the available capacity is less than the required number of bytes, the method will allocate a new buffer with an adjusted size and copy the existing data into it. This method ensures that the buffer has sufficient space to hold the desired data without causing any overflow or memory allocation issues.

sequence diagram

public ByteArrayPrimitiveBuilder append(CharBuffer src, Charset charset)

public ByteArrayPrimitiveBuilder append(CharBuffer src, Charset charset) {
    if (src == null) {
        append(NULL, 0, 4);
    } else {
        append(src.toString().getBytes(charset));
    }
    return this;
}

The append method in the ByteArrayPrimitiveBuilder class is used to add data to the byte array being built. Here is a step-by-step description of what the method is doing based on its body:

  1. It takes two parameters: src, which is a CharBuffer, and charset, which is the character set to be used for encoding the CharBuffer into bytes.

  2. It checks if the src parameter is null. If it is null, it means that there is no data to append. In this case, it calls the append method of the ByteArrayPrimitiveBuilder class with the following parameters: NULL, which is a predefined byte array representing null, 0, which is the starting index of the NULL byte array, and 4, which is the length of the NULL byte array.

  3. If the src parameter is not null, it means that there is data to append. In this case, it converts the CharBuffer to a string by calling the toString() method on it and then encodes the string into bytes using the specified charset.

  4. It then calls the append method of the ByteArrayPrimitiveBuilder class with the byte array obtained from the string encoding.

  5. Finally, it returns a reference to the ByteArrayPrimitiveBuilder object itself, allowing for method chaining.

Note: The exact behavior of the append method may depend on the implementation of the ByteArrayPrimitiveBuilder class. This description is based on the provided code snippet.

The append method in the ByteArrayPrimitiveBuilder class appends data to the byte array built by the builder.

This specific append method takes a CharBuffer and a Charset as parameters. It first checks if the CharBuffer is null. If it is null, it appends a null value indicator to the byte array.

If the CharBuffer is not null, it converts the CharBuffer to a String, gets the byte array representation of the string using the specified Charset, and appends it to the byte array.

Finally, it returns the builder instance to allow for method chaining.

sequence diagram

public ByteArrayPrimitiveBuilder append(byte[] src, int len)

public ByteArrayPrimitiveBuilder append(byte[] src, int len) {
    if (len > 0) {
        ensureCapacity(len);
        System.arraycopy(src, 0, buffer, position, len);
        position += len;
    }
    return this;
}

Method: append (in class io.nats.client.support.ByteArrayPrimitiveBuilder)

This method is used to append a byte array src to the internal buffer within the ByteArrayPrimitiveBuilder class.

Parameters:

  • src: The byte array to be appended
  • len: The length of the byte array to append

Steps:

  1. Check if the length (len) is greater than 0.
  2. If the length is greater than 0, proceed to the next step. Otherwise, the method will do nothing and return the current instance of ByteArrayPrimitiveBuilder.
  3. Ensure that the internal buffer has sufficient capacity to accommodate the byte array by invoking the ensureCapacity method.
  4. Use System.arraycopy to copy the src byte array starting from index 0 to the buffer array, starting at the current position within the buffer.
  5. Increase the position by the length of the appended byte array to maintain the correct position within the buffer.
  6. Return the current instance of ByteArrayPrimitiveBuilder, allowing for method chaining.

The append method in the ByteArrayPrimitiveBuilder class of the io.nats.client.support package is used to append a given byte array to the internal buffer.

The method takes two parameters: src, which is the byte array to be appended, and len, which specifies the number of bytes from the src array to be appended.

First, the method checks if the length len is greater than zero. If it is, the method ensures that the internal buffer has enough capacity to accommodate the additional bytes. Then, it performs a system-level array copy operation (System.arraycopy) to copy the bytes from src array starting from index 0, to the internal buffer at the current position. Finally, it updates the position variable to account for the added bytes.

The method returns the current instance of ByteArrayPrimitiveBuilder to allow for method chaining.

In summary, the append method is responsible for appending a given byte array to the internal buffer, updating the position of the buffer accordingly, and returning the updated instance of the ByteArrayPrimitiveBuilder.

sequence diagram

public ByteArrayPrimitiveBuilder append(byte[] src, int index, int len)

public ByteArrayPrimitiveBuilder append(byte[] src, int index, int len) {
    if (len > 0) {
        ensureCapacity(len);
        System.arraycopy(src, index, buffer, position, len);
        position += len;
    }
    return this;
}

The append method in the ByteArrayPrimitiveBuilder class is used to append a portion of a byte array to the current buffer. Here's a step-by-step description of what the method does based on its body:

  1. It takes three parameters: src (the source byte array), index (the starting index in the source array), and len (the length of the portion to be appended).
  2. It checks if the length provided is greater than 0.
  3. If the length is greater than 0, it proceeds to the next steps.
  4. It ensures that the current buffer has enough capacity to accommodate the portion being appended. If not, it allocates more space to the buffer.
  5. It then uses the System.arraycopy method to copy the specified portion of the source array (src) starting from the provided index (index) to the current position in the buffer.
  6. Finally, it updates the current position in the buffer by adding the length of the portion that was appended.
  7. It returns the current instance of ByteArrayPrimitiveBuilder, allowing method chaining.

Note: The append method assumes that the buffer, position, and ensureCapacity variables are defined and accessible within the ByteArrayPrimitiveBuilder class.

The append method in the ByteArrayPrimitiveBuilder class is used to add a portion of a byte array to a buffer.

The method takes three parameters: src, index, and len. src is the source array from which the byte data will be copied. index is the starting index in the source array from where the data will be copied. len is the length of the portion of the source array that will be copied.

Inside the method, the len parameter is checked to ensure that it is greater than zero. If it is, the method ensures that the buffer has enough capacity to accommodate the data being copied. Then, the System.arraycopy method is used to copy the specified portion of the source array (src) into the buffer, starting from the current position in the buffer. Finally, the position is incremented by the length of the data copied.

The method returns an instance of the ByteArrayPrimitiveBuilder class, allowing for chaining of method calls.

sequence diagram

public ByteArrayPrimitiveBuilder append(ByteArrayPrimitiveBuilder bab)

public ByteArrayPrimitiveBuilder append(ByteArrayPrimitiveBuilder bab) {
    if (bab != null) {
        append(bab.buffer, bab.length());
    }
    return this;
}

Method: append

Description:

The append method is defined in the io.nats.client.support.ByteArrayPrimitiveBuilder class. It takes a parameter bab of type ByteArrayPrimitiveBuilder and appends the contents of bab to the current ByteArrayPrimitiveBuilder object.

Steps:

  1. Check if bab is not null.
  2. If bab is not null, call the append method on the current ByteArrayPrimitiveBuilder object, passing bab.buffer and bab.length() as parameters.
  3. Return the current ByteArrayPrimitiveBuilder object after appending the contents of bab.

The append method defined in the ByteArrayPrimitiveBuilder class allows for appending the contents of another ByteArrayPrimitiveBuilder object to the current object.

The method first checks if the provided ByteArrayPrimitiveBuilder object is not null. If it isn't null, it then proceeds to append the contents of the bab object's buffer and its length to the current object's buffer using the append method defined in the same class.

Finally, the method returns a reference to the current ByteArrayPrimitiveBuilder object, allowing for method chaining and further manipulation if desired.

sequence diagram

@Override

public int appendUnchecked(byte[] src, int srcPos, int len)

@Override
public int appendUnchecked(byte[] src, int srcPos, int len) {
    System.arraycopy(src, srcPos, buffer, position, len);
    position += len;
    return len;
}

The appendUnchecked method in class io.nats.client.support.ByteArrayPrimitiveBuilder is a method that appends a specified number of bytes from a source array to a buffer array. Here is a step-by-step description of what the method does:

  1. The method receives three parameters: src, srcPos, and len.

    • src is the source array from which the bytes will be copied.
    • srcPos is the starting position of the bytes in the source array.
    • len is the number of bytes to be copied from the source array.
  2. The method uses the System.arraycopy method to copy the specified number of bytes from the source array (src) to the buffer array at the current position (position).

    • The srcPos parameter is used as the starting point in the source array.
    • The buffer array is the destination array.
    • The position is the current position/index in the buffer array at which the bytes will be copied.
    • The len parameter specifies the number of bytes to be copied from the source array.
  3. After copying the bytes, the position is incremented by the value of len. This ensures that subsequent calls to the appendUnchecked method will append to the correct position in the buffer array.

  4. The method returns the value of len, which represents the number of bytes that were successfully appended to the buffer array.

Overall, the appendUnchecked method allows for appending a specific number of bytes from a source array to a buffer array, keeping track of the current position in the buffer array for subsequent appends.

The appendUnchecked method, defined in the ByteArrayPrimitiveBuilder class of the io.nats.client.support package, is used to append a portion of a byte array to the existing buffer.

The method takes in three parameters: src, srcPos, and len.

  • src is the source byte array from which the data will be copied.
  • srcPos is the starting index in the source array from where the copy operation will begin.
  • len is the number of bytes to be copied.

Inside the method, the System.arraycopy() function is used to copy the specified portion of the source array (src) to the current position in the internal buffer. The position is then updated accordingly by incrementing it by the length of the copied data.

Finally, the method returns the length of the copied data (len).

sequence diagram

BuilderBase

BuilderBase

BuilderBase is an abstract class that serves as the base for builders in software engineering. It provides a framework for creating and manipulating objects in a flexible and modular manner. This class enables the implementation of builder patterns, allowing developers to construct complex objects step by step. The abstract nature of BuilderBase encourages extensibility and customization, making it a valuable tool for creating robust and maintainable software systems.

protected void _setAllocationSize(int allocationSizeSuggestion)

protected void _setAllocationSize(int allocationSizeSuggestion) {
    int dcas = _defaultCharsetAllocationSize();
    if (allocationSizeSuggestion <= dcas) {
        allocationSize = dcas;
    } else {
        allocationSize = bufferAllocSize(allocationSizeSuggestion, ALLOCATION_BOUNDARY);
    }
}

The _setAllocationSize method in the class io.nats.client.support.BuilderBase is used to set the allocation size for a buffer.

The method takes an integer argument allocationSizeSuggestion, which represents the suggested allocation size.

Inside the method, it first calculates the default allocation size (dcas) using the _defaultCharsetAllocationSize method.

If the allocationSizeSuggestion is less than or equal to dcas, then the allocationSize is set to dcas. Otherwise, it calculates the buffer allocation size using the bufferAllocSize method, passing the allocationSizeSuggestion and ALLOCATION_BOUNDARY as arguments. The result is then assigned to the allocationSize variable.

sequence diagram

⚠️ **GitHub.com Fallback** ⚠️