Skip to content

ZkJsonSerializer ru2

Leksiqq edited this page Feb 9, 2024 · 10 revisions

Класс ZkJsonSerializer

Основной класс, являющийся фабрикой соответствующего Json-конвертера. Также обладает свойствами, используемыми для настроек.

Важно: в данном контексте сериализация означает загрузку из ZooKeeper в Json-файл, а десериализация - загрузку из Json-файла в ZooKeeper!

Свойства

  • public ZooKeeper ZooKeeper { get; set; } - экземпляр org.apache.zookeeper.ZooKeeper из библиотеки ZooKeeperNetEx. Предполагается что соединение уже установлено, необходимая аутентификация пройдена.
  • public string Root { get; set; } = "/"; - задаёт дополнительное смемещение по дереву относительно первоначального chroot. По умолчанию имеет значение "/", соответствующее отсутствию дополнительное смещения. Таким образом, абсолютный путь узла, к которому мы обращаемся, будет /<chroot>/<Root>, где <chroot> - первоначальное смещение, определённое в строке соединения, а <Root> - значение данного свойства.

Важно: при обращении к узлу по крайней мере его родительский узел должен быть задан в ZooKeeper!

  • public List<ACL> AclList { get; set; } = [new ACL((int)Perms.ALL, Ids.ANYONE_ID_UNSAFE)]; - задаёт правило доступа ко ВСЕМ узлам создаваемого/обновляемого поддерева. По умолчанию установлен полный доступ.
  • public ZkAction Action { get; set; } = ZkAction.Replace; - задаёт способ обновления поддерева.

Методы

  • public void Reset(); - устанавливает экземпляр ZkJsonSerializer в состояние готовности. Следует вызывать после выполнения сериализации или десериализации при необходимости повторного использования экземпляра.
  • public async Task DeleteAsync(); - вспомогательный метод, не относящийся к сериализации или десериализации, но связанный с внутренней реализацией и к тому же полезный. Удаляет поддерево.
  • public async Task<bool> RootExists(); - вспомогательный метод, не относящийся к сериализации или десериализации, но связанный с внутренней реализацией и к тому же полезный. Сообщает, присутствует ли в ZooKeeper данные по пути, заданном свойством Root.
  • public async Task CreateRoot(); - вспомогательный метод, не относящийся к сериализации или десериализации, но связанный с внутренней реализацией и к тому же полезный. Создаёт в ZooKeeper путь, заданный свойством Root, если он отсутствует.
  • public JsonElement IncrementalSerialize(string scriptPrefix); - считывает дерево с обработкой команд простого встроенного языка, позволяющего повторное использование частей JSON-файла.

Команды встроенного языка

<prefix> назначается исходя из личных предпочтений. Для работы с конкретным префиксом метод IncrementalSerialize(<prefix>) вызывается с ним в качестве аргумента.

  • <prefix>:base - название поля, значением которого является абсолютный или относительный путь к объекту, который будем называть базовым, элементы которого будут скопированы в текущий объект (наследник). При этом
  1. копируются все свойства базового объекта.
  2. Свойства, содержащиеся как в базовом так и в наследнике, принимают значения, установленные в наследнике.
  3. Свойства наследника, названия которых начинаются со знака -, удаляются.

Также можно добавить свойства, не содержащиеся в базовом объекте. Можно наследовать от нескольких объектов, в этом случае пути к базовым объектам перечисляются в массиве. Важно: все пути, используемые для ссылок на базовые объекты, должны указывать на элементы внутри того же JSON-файла, загруженного в Zookeeper!

  • <prefix>:value(<path>) - значение поля или элемент массива, которое заменяется на значение элемента-донора, указанного абсолютным или относительным путём . Вычисление данного значения производится после применения всех команд <prefix>:base. Ограничения:
  1. значение элемента-донора должно быть терминальным, то есть не объектом и не массивом.
  2. Значение элемента-донора не должно содержать команд.

Важно: все элементы-доноры должны находиться внутри того же JSON-файла, загруженного в Zookeeper!

  • <prefix>:path([from,[count]]) - значение поля или элемент массива, которое заменяется на значение отрезка абсолютного пути к текущему элементу. Границы этого отрезка выбираются с помощью целочисленных параметров from и count. Отрицательное значение параметра from является сокращённой записью для отсчёта с конца.
  • <prefix>:eval(<arg>) - значение поля или элемент массива, которое заменяется на строку, полученную после преобразования параметра <arg>. Строка <arg> может содержать команды <prefix>:value(<path>) и <prefix>:path([from,[count]]), которые будут заменены на вычисленные значения.

Пример работы приведён в Демо:ZkJsonDemo.

Пример

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

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

Кроме перечисленного, в классе ZkJsonSerializer реализованы абстрактные методы родительского класса System.Text.Json.Serialization.JsonConverterFactory.

Примеры

Общие действия

    ZooKeeper zk;

    // Создаётся экземпляр `ZooKeeper`, ожидается соединение с кластером ...

    ...

    // Соединение установлено!

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

Чтение Json-файла из ZooKeeper

    JsonSerializerOptions serializerOptions = new()
    {
        WriteIndented = true, // Пусть будет красиво
    };

    // Обязательно добавляем наш экземпляр ZkJsonSerializer в список конвертеров!

    serializerOptions.Converters.Add(factory);

    // Запишем файл в поток:

    Stream output;

    // Открываем поток как-то

    ...

    // Пишем файл в поток, ZkStub.Instance - просто затычка, serializerOptions - обязательно!

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

    // Или в асинхронном коде: 
    // await JsonSerializer.SerializeAsync(output, ZkStub.Instance, serializerOptions);

    // Получим `System.Text.Json.JsonElement`, чтобы его обходить или десериализовать в другой объект:
    // Сначала сбрасываем состояние фабрики

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

Запись Json-файла в ZooKeeper

    JsonSerializerOptions serializerOptions = new();

    // Обязательно добавляем наш экземпляр ZkJson в список конвертеров!
    serializerOptions.Converters.Add(factory);

    // Будем читать файл из потока:

    Stream input;

    // Открываем поток как-то

    ...

    factory.Action = ZkAction.Replace; // или ZkAction.Update, если обновляем отдельные поля

    // Читаем файл из потока, ZkStub - просто тип-затычка, serializerOptions - обязательно!

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

    // Или в асинхронном коде: 
    // await JsonSerializer.DeserializeAsync<ZkStub>(options.Reader, serializerOptions);

    // Пусть у нас есть объект `System.Text.Json.JsonElement`, в который мы сериализовали другой объект, 
    // и мы запишем в `ZooKeeper` его:

    // Сначала сбрасываем состояние фабрики

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

Удаление поддерева в ZooKeeper

    factory.DeleteAsync().Wait();

    // Или в асинхронном коде: 
    // await factory.DeleteAsync();

Начало: (Обзор) Дальше: (ZkAction)