Commons - fincity-india/nocode-saas GitHub Wiki

Introduction

Commons is the base library for the platform. It provides the common functionality across the services. It is used in multiple services. The library is written by us. This documentation is strictly for the 💻 people.

Configuration

"AbstractBaseConfiguration.java" is the base configuration class for the platform. Every Spring configuration class will extend this class. It provides the common functionality across the services.

We initialize the object of the ObjectMapper class. This object is used to convert any java object to JSON and vice versa. Also, we have some custom serializers and de-serializers for the ObjectMapper (Discussed in detail in the Jackson Modules section). Redis Configuration is also initialized in this class. We use Redis as the second layer of caching. The first layer is the in-memory cache called Caffeine. Default CORS Mapping is added there any additional mapping can be added in the service specific configuration class.

Controller Advice

"ControllerAdvice.java" is the base controller advice class for the platform. This class handles all the errors and convert them into proper error JSON output. It provides the common functionality across all the platform service. If a non-Generic exception is thrown, this controller advice transforms it into a Generic Exception and triggers a 500 Internal Server Error.

Message Service

Throughout the platform we throw many exceptions and the "AbstractMessageService.java" provides the common functionality to handle the exceptions and retrieve the message from the message properties file and wrap properly in a Mono.

Generic Exception

This is a Runtime Exception class to wrap the Http return code when an exception is thrown. It is also used to throw exception with a message when used in methods in Message Service.

Redis Codecs

We have JSON and Object codecs are used to serialize and de-serialize the objects to and from Redis. While debugging, it is really helpful to see what is the data in Redis, we use JSON codec. RedisObjectCodec simply convert the object to byte array using Object output and input stream.

Data File Reader/Writer

We have our own data file reader and writer that suppports reading and writing of the data in CSV, XLS, XLSX, TSV, JSON, JSONL formats. The reader and writer are used to read and write the data from and to the file. The reader and writer are standalone classes and can be used in any service.

JSON Flattener/Unflattener

These pair or utility classes are used to flatten and unflatten the JSON. The JSON Flattener is used to flatten the JSON to a single level and the JSON Unflattener is used to unflatten the JSON to the original structure.

For example:

```json
{
"a": {
    "b": {
    "c": 1,
    "d": 2
    }
}
}
```

will be flattened to

```json
{
"a.b.c": 1,
"a.b.d": 2
}
```

GSON Adapter

We have a LocalDateTime gson adapter used when converting objects into GSON to Java Object or JSON and vice versa.

Jackson Modules

When we send data through REST API calls, Spring uses Jackson to convert them back and froth from Java objects and JSON. We have some custom modules for AbstractCondition (More on this in AbstractLayer), LocalDateTime, Sort and Tuple.

Data Structures

A Doubly linked Circular Linked List is implemented with minimal implementation is created with speed as the primary concern.

Utility Classes

We have a lot of utility classes implemented in the Commons that are used across the platform services.

BooleanUtil.java

As the name suggest, this utility is for Boolean values.

  • parse Method - public static Boolean parse(Object object) When the object sent is

    • null : returns null
    • Boolean type : returns as is
    • Byte type : returns true if the byte is not 0, false otherwise
    • any other type : calls the toString method and checks if it is "true" or "false" and returns the boolean value accordingly.
    • If the object is not null and not of the above types, it throws an exception.
  • safeValueOf Method - public static boolean safeValueOf(Object object) When the object sent is

    • null : returns false
    • Boolean type : returns as is
    • Byte type : returns true if the byte is not 0, false otherwise
    • any other type : calls the toString method and checks if it is "true" or "yes" or "y" or "t" or "on" and returns the boolean value accordingly.
    • If it is none of the above, it returns false.
  • safeValueOfWithEmpty Method - public static Mono<Boolean> safeValueOfWithEmpty(Object b) works the same as safeValueOf but returns Mono and Mono.empty() if the object evaluated as false.

ByteUtil.java

Has couple of constants for one and zero.

CodeUtil.java

This utility is for generating the codes like login code or otp or any other code. It has a method public static String generate(CodeGenerationConfiguration config) which takes the configuration object and returns the generated code. We have avoided vowels and letter 'Y' is we won't generate any offensive words. The configuration object has the following fields:

  • length : The length of the code to be generated.
  • numeric : Default is true, if true will have digits in the code from 0-9.
  • lowercase : Default is false, if true will have lowercase alphabets in the code from b-z without any vowels and letter y.
  • uppercase : Default is false, if true will have uppercase alphabets in the code from B-Z without any vowels and letter Y.
  • specialChars : Default is false, if true will have special characters in the code from !@#$
  • seperators : List of locations where you want to have a separator in the code. For example, if the length is 6 and the separator is at 2, the code will be like "AB-CD" where A, B, C, D are the characters generated.
  • separator : The character to be used as a separator. Default is '-'.

CommonsUtil.java

This utility has only one method called public static <T> T nonNullValue(T... values) which returns the first non-null value from the list of values. If all the values are null, it returns null.

ConditionUtil.java

This utility has only one method parameterMapToMap that will help convert the request parameter map in an HTTP request to a condition object. When a single condition is present, a FilterCondition object is returned, applying the "Equals" operator to the field and value. If the value comprises a list, the "IN" operator is utilized. For multiple conditions, a ComplexCondition object is returned, encapsulating all conditions as FilterCondition objects, linked by the "AND" operator.

For example: If the query string is ?name=John then instance of FilterCondition with field and value as "name" and "John" respectively is returned with "Equals" operator.

If the query string is ?name=John&name=Jane then instance of FilterCondition with field and value as "name" and ["John", "Jane"] respectively is returned with "IN" operator.

If the query string is ?name=John&age=25 then instance of ComplexCondition with two FilterCondition objects is returned with "AND" operator.

EqualsUtil.java

This utility has only one method called public static <T> boolean safeEquals(T a , T b) which returns true if both the objects are equal. When both objects are null, the result is true. If only one object is null, the result is false. When neither object is null, the "equals" method of the first object is invoked and its result is returned.

HashMapUtil.java

This utility works like Map.of method but returns a HashMap.

LogUtil.java

This utility is used to log something if there is a debug key in the reactive context.

MapUtil.java

This utility has only one method public static void setValueInMap(Map<String, Object> map, String key, Object value) which sets the value in the map if the value is not null. It is used when the Map is a complex map which contains maps that contains other maps.

For example: the key is "a.b[3].c" then the value is set in the map as follows:

map.get("a").get("b").get(3).put("c", value);

However, the unique distinction here is that if the map "a" doesn't exist, it's created. Similarly, if the array "b" doesn't exist, it's instantiated. If the index 3 doesn't exist, it's generated. Lastly, if the map "c" is missing, it's created and its value is set.

The first object has to be a map always, since this method takes Map

MathUtil.java

This utility has couple of methods max and min which function as Javascript Math.max and Math.min with two exceptions. These methods only work with float types and they throw Exception when there are no arguments.

StringUtil.java

This utility provides functionality for String operations.

  • safeValueOf Method public static String safeValueOf(Object obj, String... defaultValue) returns the toString value of the object if it is not null, otherwise returns the default value. If the default value is not provided, it returns a null;

  • safeIsBlank Method public static boolean safeIsBlank(Object object) returns true if object is null or toString value is blank.

  • safeEquals Method public static boolean safeEquals(String str, String str2) similar implementation of EqualsUtil.

  • onlyAlphabetAllowed Method returns false if the argument is null or a string that has any characters other than a-z lowercase or uppercase, else return true.

  • removeLineFeedOrNewLineChars Method removes all the '\r' and '\n' characters in the ending of a string.

  • removeSpecialCharacters Method returns only characters from a string that are a-z lowercase or uppercase.

UniqueUtil.java

Everyone knows what is the Universally Unique Identifier (UUID). Here is a link to a gripping read of RFC from IETF https://www.ietf.org/rfc/rfc4122.txt. It explains how UUID is generated and what are the different versions of UUID. With that understanding we know nothing is truly random.

The UUID is 128 bit, it is 16 bytes and when represented in Hexadecimal it requires 32 characters and 4 hyphens bringing tally up to 36 characters. But that is very long, here we came up with multiple shorter variants of UUID.

  • base36UUID - This method returns a 25 character long UUID. It is a base36 representation [0123456789abcdefghijklmnopqrstuvwxyz] of UUID, which is a good balance between length and randomness.

  • shortUUID - This method returns a 13-15 character long UUID. It is a base62 representation [0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ] of UUID, which is better than base36UUID.

  • uniqueName - This method returns a unique name with given prefixes restricted to a certain max length. It contains letters (converts uppercase to lowercase), numbers and underscore.

  • uniqueNameOnlyLetters - This method returns a unique name with given prefixes restricted to a certain max length. It only contains letters.

⚠️ **GitHub.com Fallback** ⚠️