Skip to content

ZkJsonSerializer en2

Leksiqq edited this page Feb 9, 2024 · 3 revisions

Attention! This article, as well as this announcement, are automatically translated from Russian.

Class ZkJsonSerializer

The main class, which is the factory of the corresponding Json converter. Also has properties used for settings.

Important: in this context, serialization means loading from ZooKeeper into a Json file, and deserialization means loading from a Json file into ZooKeeper!

Properties

  • public ZooKeeper ZooKeeper { get; set; } - an instance of org.apache.zookeeper.ZooKeeper from the ZooKeeperNetEx library. It is assumed that the connection has already been established and the necessary authentication has been completed.
  • public string Root { get; set; } = "/"; - specifies an additional offset along the tree relative to the original chroot. The default value is "/", corresponding to no additional offset. Thus, the absolute path of the node we are accessing will be /<chroot>/<Root>, where <chroot> is the initial offset defined in the connection string, and <Root> is the value of this property.

Important: When accessing a node, at least its parent node must be set to ZooKeeper!

  • public List<ACL> AclList { get; set; } = [new ACL((int)Perms.ALL, Ids.ANYONE_ID_UNSAFE)]; - sets the rule for access to ALL nodes of the created/updated subtree. The default is Full Control.
  • public ZkAction Action { get; set; } = ZkAction.Replace; - sets the method for updating the subtree.

Methods

  • public void Reset(); - sets the ZkJsonSerializer instance to the ready state. Should be called after serialization or deserialization is performed when the instance needs to be reused.
  • public async Task DeleteAsync(); - an auxiliary method not related to serialization or deserialization, but related to the internal implementation and also useful. Deletes a subtree.
  • public async Task<bool> RootExists(); - an auxiliary method not related to serialization or deserialization, but related to the internal implementation and also useful. Reports whether ZooKeeper contains data at the path specified by the Root property.
  • public async Task CreateRoot(); - an auxiliary method not related to serialization or deserialization, but related to the internal implementation and also useful. Creates the path specified by the Root property in ZooKeeper if it is missing.
  • public JsonElement IncrementalSerialize(string scriptPrefix); - reads a tree with simple built-in language command processing, allowing parts of a JSON file to be reused.

Built-in language commands

<prefix> is assigned based on personal preference. To work with a specific prefix, the IncrementalSerialize(<prefix>) method is called with it as an argument.

  • <prefix>:base - the name of the field, the value of which is the absolute or relative path to the object, which we will call base, the elements of which will be copied to the current object (successor). Wherein
  1. all properties of the base object are copied.
  2. Properties contained in both the base and the heir take on the values ​​set in the heir.
  3. Properties of the heir whose names begin with the - sign are deleted.

You can also add properties that are not contained in the base object. You can inherit from multiple objects, in which case the paths to the base objects are listed in an array. Important: All paths used to reference base objects must point to elements within the same JSON file loaded into Zookeeper!

  • <prefix>:value(<path>) - the field value or array element that is replaced with the value of the donor element specified by the absolute or relative path . This value is calculated after all <prefix>:base commands have been applied. Restrictions:
  1. The value of the donor element must be terminal, that is, not an object or an array.
  2. The value of the donor element must not contain commands.

Important: all donor elements must be inside the same JSON file loaded into Zookeeper!

  • <prefix>:path([from,[count]]) - field value or array element, which is replaced by the value of the absolute path segment to the current element. The boundaries of this segment are selected using the integer parameters from and count. A negative value for the from parameter is shorthand for counting from the end.
  • <prefix>:eval(<arg>) - field value or array element that is replaced with the string obtained after converting the <arg> parameter. The <arg> line can contain <prefix>:value(<path>) and <prefix>:path([from,[count]]) commands, which will be replaced with the calculated values.

An example of work is given in Demo:ZkJsonDemo.

Example

     ZkJsonSerializer configSerializer = new()
     {
         ...
     };
     configSerializationOption.Converters.Add(configSerializer);

     TConfig Config = JsonSerializer.Deserialize<TConfig>(
         configSerializer.IncrementalSerialize("base"),
         configDeserializationOption
     );

In addition to the above, the ZkJsonSerializer class implements abstract methods of the parent class System.Text.Json.Serialization.JsonConverterFactory.

Examples

General actions

     ZooKeeper zk;

     // An instance of `ZooKeeper` is created, a connection to the cluster is expected...

     ...

     // Connection established!

     ZkJsonSerializer factory = new()
     {
         ZooKeeper = zk,
     };

Reading a Json file from ZooKeeper

     JsonSerializerOptions serializerOptions = new()
     {
         WriteIndented = true, // Let it be beautiful
     };

     // Be sure to add our ZkJsonSerializer instance to the list of converters!

     serializerOptions.Converters.Add(factory);

     // Write the file to the stream:

     Stream output;

     // Open the stream somehow

     ...

     // We write the file to the stream, ZkStub.Instance is just a plug, serializerOptions is a must!

     JsonSerializer.Serialize(output, ZkStub.Instance, serializerOptions);

     // Or in asynchronous code:
     // await JsonSerializer.SerializeAsync(output, ZkStub.Instance, serializerOptions);

     // Get `System.Text.Json.JsonElement` to bypass it or deserialize it into another object:
     // First reset the factory state

     factory.Reset();
     JsonElement jsonElement = JsonSerializer.SerializeToElement(ZkStub.Instance, serializerOptions);

Writing a Json file to ZooKeeper

     JsonSerializerOptions serializerOptions = new();

     // Be sure to add our ZkJson instance to the list of converters!
     serializerOptions.Converters.Add(factory);

     // We will read the file from the stream:

     Stream input;

     // Open the stream somehow

     ...

     factory.Action = ZkAction.Replace; // or ZkAction.Update, if we update individual fields

     // Read the file from the stream, ZkStub is just a plug type, serializerOptions is a must!

     JsonSerializer.Deserialize<ZkStub>(input, serializerOptions);

     // Or in asynchronous code:
     // await JsonSerializer.DeserializeAsync<ZkStub>(options.Reader, serializerOptions);

     // Let's say we have a `System.Text.Json.JsonElement` object into which we have serialized another object,
     // and we will write it in `ZooKeeper`:

     // First reset the factory state

     factory.Reset();
     JsonSerializer.Deserialize<ZkStub>(jsonElement, options);

Removing a subtree in ZooKeeper

     factory.DeleteAsync().Wait();

     // Or in asynchronous code:
     // await factory.DeleteAsync();

Start: (Review) Next: (ZkAction)