Быстрый старт#
О документе#
Документ предназначен для разработчиков приложений, использующих компонент DataSpace.
Цель документа — научить разработчика формированию артефактов, необходимых для работы серверной части (DataSpace Core) и клиентской части (SDK).
Часть 1: Сборка архетипа#
В рамках данного этапа с помощью полученного дистрибутива необходимо собрать проект-архетип.
Для сборки архетипа необходимо использовать плагин mvn-archetype-plugin.
Дистрибутив компонента DSPC представляет собой ZIP-архив dspc-bin-<номер дистрибутива>-distrib.zip, содержащий папки:
package/docker— папка с содержимым для формирования базовых образов сервисов DataSpace;package/sdk/m2— папка с упакованными в JAR-архивы классами и конфигурационными файлами.
Внимание!
В некоторых организациях дистрибутив распаковывается централизовано в корпоративное хранилище артефактов (например, Nexus). В таком случае, нет необходимости скачивать полный zip-архив. Все необходимые артефакты можно найти в корпоративном хранилище по соответствующим groupId и artifactId. Можно сразу же переходить к следующей части данной инструкции: "Часть 2: Создание проекта".
Для сборки архетипа необходимо выполнить следующие шаги:
Внимание!
Если дистрибутив не распаковывался в локальную папку .m2, а используется корпоративное хранилище артефактов и, соответственно, кастомизированный settings.xml c прописанными в нем путями к корпоративным хранилищам, то необходимо в maven-команды добавить атрибут
-s <путь к settings.xml>. Например,mvn ... -s C:\users\имя пользователя\.m2\mySettings.xml
Шаг 1. Все содержимое папки m2 (расположено по пути apt-<номер_версии>-distrib/dspc-<номер_версии>-distrib/package/sdk/mvn/m2/) скопировать в репозиторий Maven.
По умолчанию репозиторий Maven расположен по следующему пути:
* ~/.m2/repository для *Nix-систем;
* c:\Users{имяПользователя}.m2\repository для Windows.
Примечание
Если требуется использование при сборке централизованного maven-репозитория, необходимо запустить скрипт upload.sh (расположен по пути apt-scripts-<номер дистрибутива>-distrib.zip/package/scripts/ansible-playbooks/) для загрузки артефактов в данный репозиторий:
bash upload.sh <полный путь к папке package/sdk/m2> <полный путь к файлу settings.xml> <URL с указанием имени репозитория (например, http://127.0.0.1/repository/maven-releases)> <ID репозитория в settings.xml>
Шаг 2. Внутри репозитория, открыть созданную папку sbp/com/sbt/dataspace/dataspace-model-archetype/{версия архетипа} и выполнить команду для сборки архетипа:
mvn org.apache.maven.plugins:maven-archetype-plugin:{версия плагина}:update-local-catalog -f dataspace-model-archetype-{версия архетипа}.pom
В данной команде:
{версия плагина}— версия плагина maven-archetype-plugin, рекомендуется указать версию 3.2.0;{версия архетипа}— версия архетипа dataspace (совпадает с версией артефакта dataspace-bom из дистрибутива), артефакт расположен по пути sbp.com.sbt.dataspace.dataspace-model-archetype.
Особенности для ОС Windows
Для Windows при использовании PowerShell вы не увидите результаты выполнения, так как командное окно закрывается сразу после выполнения команды, изменить это поведение на текущий момент времени нельзя. Чтобы увидеть лог-запись, лучше использовать CMD.
В случае, если политики безопасности Windows не позволяют запускать mvn вне ее собственной папки, необходимо указать полный путь к pom-файлу.
Пример заполненной команды для сборки архетипа:
mvn org.apache.maven.plugins:maven-archetype-plugin:3.2.0:update-local-catalog -f dataspace-model-archetype-4.2.34.pom
При отработке команды, Maven скачает требуемые файлы и соберет архетип проекта:
[INFO] Scanning for projects...
Downloading from internal: http://example.repository.ru/nexus/content/groups/internal/org/apache/archetype/archetype-packaging/3.2.0/archetype-packaging-3.2.0.pom
Downloaded from internal: http://example.repository.ru/nexus/content/groups/internal/org/apache/archetype/archetype-packaging/3.2.0/archetype-packaging-3.2.0.pom
...
[INFO] ---------------
[INFO] BUILD SUCCESS
[INFO] ---------------
[INFO] Total time: 00:45 min
[INFO] Finished at: 2021-06-01T15:11:36+03:00
[INFO] ---------------
Собранный архетип проекта можно использовать в качестве шаблона для формирования проектов, использующих возможности DataSpace.
Часть 2: Создание проекта#
В данном разделе объясняется, каким образом собранный архетип можно использовать для формирования Java-проекта, который будет использовать DataSpace.
Перейдите в каталог, в котором хотите разместить новый проект. Для создания Java-проекта, выполните следующую команду:
mvn -DgroupId=ru.test -DartifactId=quickstart -Dversion=DEV-SNAPSHOT -DmodelName=quickstart -DdataspaceBomVersion={версия артефакта dataspace-bom} -DarchetypeGroupId=sbp.com.sbt.dataspace -DarchetypeArtifactId=dataspace-model-archetype -DarchetypeVersion={версия архетипа} -DarchetypeCatalog=local org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate
где:
-DgroupId— groupId вашего проекта;-DartifactId— artifactId вашего проекта;-DmodelName— название модели (см. документ "Руководство по ведению модели")-DdataspaceBomVersion— необходимо указать версию dataspace-bom из дистрибутива, артефакт расположен по пути sbp.com.sbt.dataspace.dataspace-bom;-DarchetypeVersion— необходимо указать версию dataspace-model-archetype из дистрибутива, артефакт расположен по пути sbp.com.sbt.dataspace.dataspace-model-archetype (совпадает с версией артефактаdataspace-bom).
Особенности для ОС Windows
Могут быть особенности, если ваши политики безопасности запрещают запускать Maven, находясь в другой папке, запрещают запускать его из любой другой папки и он не прописан в системных переменных.
Имеется несколько способов решения проблемы:
Способ 1. Утилита CMD Для запуска утилиты mvn укажите путь к ней в кавычках, так как вероятнее всего путь к ней будет содержать пробелы. Не забывайте про "./" для запуска. Кроме того, заключите в кавычки все параметры Maven, начинающиеся с -D.
текущий/каталог> "C:\maven\lib\maven3\bin\./mvn" "-DgroupId=sbp.test" "-DartifactId=quickstart" "-Dversion=DEV-SNAPSHOT" "-DmodelName=quickstart" "-DdataspaceBomVersion=<версия bom>" "-DarchetypeGroupId=sbp.com.sbt.dataspace" "-DarchetypeArtifactId=dataspace-model-archetype" "-DarchetypeVersion=<версия архетипа>" "-DarchetypeCatalog=local" org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generateСпособ 2. Утилита PowerShell Вызов утилиты mvn необходимо дополнить знаком "&", чтобы PowerShell не воспринимала следующий "-" как оператор. Не забывайте про "./" для запуска утилиты.
PS текущий/каталог> & "C:\maven\lib\maven3\bin\./mvn" -DgroupId=sbp.test -DartifactId=quickstart -Dversion=DEV-SNAPSHOT -DmodelName=quickstart -DdataspaceBomVersion=<версия bom> -DarchetypeGroupId=sbp.com.sbt.dataspace -DarchetypeArtifactId=dataspace-model-archetype -DarchetypeVersion=<версия архетипа> -DarchetypeCatalog=local org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate
При вводе команды укажите следующие параметры:
groupId— идентификатор группы будущего maven-проекта. Рекомендуется заменить на другое значение.artifactId— идентификатор корневого артефакта создаваемого maven-проекта. Рекомендуется заменить на другое значение.version— версия будущего проекта. Рекомендуется заменить на другое значение.dataspaceBomVersion— версия dataspace-bom.modelName— имя модели в сформированном файле. Имя модели должно включать только латинские символы. Текущее значение:quickstart.archetypeGroupId— идентификатор группы Maven-архетипа, из которого будет сгенерирован проект. Оставить без изменений.archetypeArtifactId: идентификатор имени Maven-архетипа. Значение:dataspace-model-archetype. Оставить без изменений.archetypeVersion: версия архетипа (совпадает с версией bom).org.apache.maven.plugins: версия Maven-плагина.RELEASE— последняя релизная версия.
Шаг 2. Во время выполнения Maven запросит подтверждение переданных параметров. Для подтверждения параметров достаточно нажать клавишу Enter.
...
modelName: quickstart
Y: :
[INFO] ---------------------
[INFO] Using following parameters for creating project from Archetype: dataspace-model-archetype:RELEASE
[INFO] ---------------------
[INFO] ...
[INFO] Project created from Archetype in dir: C:\projects\quickstart
[INFO] ---------------
[INFO] BUILD SUCCESS
[INFO] ---------------
[INFO] Total time: 01:13 min
[INFO] Finished at: 2021-06-01T15:30:36+03:00
[INFO] ---------------
После выполнения команды в текущей папке будет создан Java-проект.
Сформированный Java-проект будет включать в себя шаблонную модель предметной области и шаблонный функциональный тест.
Со структурой артефактов можно ознакомиться в документе "Структура артефактов DataSpace".
С изменениями шаблонного проекта можно ознакомиться в CHANGELOG.md в корневой папке сгенерированного проекта (начиная с версии 1.7 продукта).
Часть 3: Структура модели данных#
В данном разделе объясняется структура демонстрационного проекта.
Сформированный Java-проект включает в себя шаблонную модель предметной области и шаблонный функциональный тест.
Имя файла модели: model.xml.
Имя файла теста: ModelTest.java.
Демонстрационный файл модели включает в себя два класса — "Книжный магазин" (BookStore) и "Книга" (Book). Между классами действует соотношение "1:*" (в книжном магазине может быть много экземпляров книг). Для этого соотношения корнем агрегата должен выступать "книжный магазин".
Для задания связи между сущностями используются следующие свойства:
BookStore.books. Особые свойства:collection="set"для задания множественности иmappedBy="bookStore"для задания имени поля на обратном конце ассоциации.Book.bookstore. Особое свойство:parent="true"для ссылки на корень агрегата.
Демонстрационная модель показана в примере ниже.
<model model-name="quickstart" version="DEV-SNAPSHOT" >
<class name="BookStore" label="Книжный магазин">
<property name="name" type="String" label="Название"/>
<property name="address" type="String" label="Адрес"/>
<property name="books" type="Book" label="Книги" collection="set" mappedBy="bookStore"/>
</class>
<class name="Book" label="Книга">
<property name="bookStore" type="BookStore" label="Книжный магазин" parent="true"/>
<property name="name" type="String" label="Название"/>
<property name="author" type="String" label="Автор"/>
<property name="isbn" type="String" label="Код ISBN"/>
</class>
</model>
В дальнейшем шаблонную модель данных можно дорабатывать в зависимости от имеющихся потребностей. Дополнительную информацию о способах разработки модели можно найти в документе "Руководство по ведению модели".
Часть 4: Структура демонстрационного теста#
Файл с демонстрационным тестом расположен внутри собранного с помощью артефакта проекта по следующему пути: model-local-test/src/test/java/ru/test/ModelTest.java.
В данный файл включен один тест. Тест последовательно выполняет шаги тестового сценария.
Примечание
Каждый шаг теста реализован как отдельная функция.
Последовательность выполнения шагов показана в примере кода ниже.
public class ModelTest extends BaseTest {
@Test
public void demoTest() throws Throwable {
// Проверка 1. Создание объектов и получение их свойств.
createBookStoreWithBook();
// Проверка 2. Создание нескольких агрегатов и поиск по их свойствам.
createOtherBookStoreWithAnyBooks();
// Проверка 3. Поиск по связанным сущностям.
createThirdBookStoreWithAnyBooks();
// Проверка 4. Вывод всех книг
searchAllBooksInAllBookStores();
// Проверка 5. Изменение свойств объекта.
searchByMaskAndUpdateAddressForBookStore();
// Проверка 6. Проверка идемпотентности вызовов.
createBookWithIdempotence();
// Проверка 7. Оптимистическая блокировка при обновлении объекта.
updateBookWithOptimisticLock();
}
}
Часть 5: Локальная сборка проекта#
В рамках этого шага необходимо выполнить следующие действия:
Скомпилировать Java-классы шаблонного проекта (без выполнения тестов).
Выполнить тесты шаблонного проекта.
Для компиляции шаблонного проекта (без тестов) необходимо выполнить любой пункт из следующих:
При запуске из среды разработки в оснастке Maven выполнить команды
cleanиinstallдля корневого проекта с отключенными тестами.При запуске из терминала или командной строки использовать следующую команду:
mvn clean install -DskipTests -P {профиль}.
В результате компиляции Maven создаст папку target и поместит в нее скомпилированные Java-классы и архивы.
Примечание
Скомпилированные файлы и архивы нужны для выполнения тестов. Поэтому запуск сборки с включенными тестами приведет к ошибке.
Для прогона шаблонных тестов необходимо произвести сборку с включенными тестами:
При запуске из среды разработки в оснастке Maven выполнить команды
cleanиinstallдля корневого проекта с включенными тестами.При запуске из терминала или командной строки использовать команду:
mvn clean install -P {профиль}. Не использовать ключ-DskipTests!
Тесты выполняются в следующей последовательности:
Maven запускает тестовый API.
Maven запускает тестовую базу данных в памяти.
Maven проводит тесты.
Maven уничтожает экземпляры запущенных сервисов.
Часть 6: Дальнейшая разработка проекта#
В шаблон проекта включена демонстрационная модель и тесты. Данную модель и тесты можно дорабатывать и изменять.
Внимание!
Классы демонстрационной модели используются в тестах. В случае удаления или изменения классов демонстрационной модели при прогоне тестов могут возникнуть ошибки. Поэтому важно отслеживать состояние демонстрационной модели и использующих ее тестов.
Включенный в шаблон тест расположен по следующему пути: {root}/model-local-test/src/tyest/java/ru/test/ModelTest.java.
В случае удаления демонстрационных классов из модели, достаточно удалить из теста (или закомментировать в нем) содержимое метода demoTest().
Также из файла ModelTest.java необходимо удалить импорты ставших недействительными классов (SimpleEntity*).
После обновления тестового класса сборку необходимо перезапустить.
Часть 7: Описание демонстрационного теста#
Демонстрационный тест последовательно выполняет следующие проверки:
Создание объектов и получение их свойств.
Создание нескольких агрегатов и поиск по их свойствам.
Поиск по связанным сущностям.
Вывод всех книг.
Изменение свойств объекта.
Проверка идемпотентности вызовов.
Оптимистическая блокировка при обновлении объекта.
Для работы с тестами предназначен файл, расположенный по следующему пути: {root}/model-local-test/src/test/java/ru/test/ModelTest.java.
7.1. Создание объектов и получение их свойств#
Примечание
В рамках данного шага (функция
createBookStoreWithBook) будут созданы две связанные сущности: "книжный магазин" и "книга". В дополнение к этому свойства созданных сущностей будут выведены в лог-запись.
Все операции создания и изменения сущностей необходимо делать в рамках пакета команд. Операции создания связанных сущностей можно делать в рамках одного пакета:
Packet createPacket = new Packet();
Создайте тестовые сущности из нового пакета. В объектах пропишите требуемые связи. Для задания параметра необходимо использовать метод с префиксом set и названием свойства в camelCase (например, setAddress()):
// Создание магазина
BookStoreRef chitayGorodBookStoreRef = creationPacket.bookStore.create(bookstore -> {
bookstore.setAddress("Большая Садовая ул., 110 стр. 131, Ростов-на-Дону");
bookstore.setName("Читай-город");
});
// Создание книги
BookRef tomSawyerBookRef = creationPacket.book.create(book -> {
book.setAuthor("Марк Твен");
book.setName("Том Сойер и Гек Финн");
book.setIsbn("5-7516-0502-0");
book.setBookStore(chitayGorodBookStoreRef); // задание связи книги с магазином
});
Тесты создания и получения сущностей необходимо отправить на выполнение:
dataspaceCorePacketClient.execute(creationPacket);
Также можно создавать пакеты на чтение:
Packet readingPacket = new Packet();
Из созданных объектов DataSpace напрямую можно получить только идентификатор. Поэтому получать свойства объектов необходимо через класса-обертку с суффиксом Get. Для получения свойств объектов необходимо использовать методы с префиксом with:
BookGet tomSawyerBook = readingPacket.book.get(tomSawyerBookRef, book -> {
book.withAuthor();
book.withName();
book.withIsbn();
});
В демонстрационный тест добавлены проверки:
Assertions.assertEquals(tomSawyerBook.getAuthor(), "Марк Твен");
7.2. Создание объектов в нескольких агрегатах и поиск объектов по свойствам#
В рамках данного шага (функция createOtherBookStoreWithAnyBooks демонстрационного проекта) будет сделано следующее:
В существующий магазин будет добавлена новая книга.
Будет создан магазин.
Будут созданы книги.
Созданные книги будут добавлены в новый магазин.
В начале метода показан поиск объекта по значению параметра. Сначала необходимо сделать коллекцию с выборкой по требуемым свойствам объектов:
Для названия класса коллекции необходимо использовать суффикс
CollectionWith.Для создания коллекции необходимо использовать метод с префиксом
select(например,selectBookStoreиз классаGraphCreator).Для выбора получаемых свойств использовать методы с префиксом
with.Для задания условия выборки использовать метод
setWhereс лямбда-функцией типа*Grasp.Для оформления параметра использовать функцию с суффиксом
Eq(точное совпадение),Like(поиск по маске), илиContains(одно из значений).
BookStoreCollectionWith<BookStoreGrasp> bookStoreCollectionWith = GraphCreator.selectBookStore()
.setWhere(bookStoreGrasp -> bookStoreGrasp.nameLike("Читай-город%"));
GraphCollection<BookStoreGet> bookStoreGets = dataspaceCoreSearchClient.searchBookStore(bookStoreCollectionWith);
BookStoreRef bookStoreRef = BookStoreRef.of(bookStoreGets.get(0).getObjectId());
Между книжными магазинами и экземплярами книг действует соотношение "1:*". Поэтому операции создания объектов необходимо объединять в пакеты с разбивкой по объектам "Книжный магазин":
// Создать пакет 1 — существующий магазин (BookStore 1)
Packet packet1 = new Packet();
// Создать книгу (Book 1) и добавить книгу в BookStore 1.
dataspaceCorePacketClient.execute(packet1);
// Создать пакет 2 — новый магазин магазин (BookStore 1)
Packet packet1 = new Packet();
// Создать книгу (Book 2) и добавить книгу в BookStore 2.
// Создать книгу (Book 3) и добавить книгу в BookStore 2.
dataspaceCorePacketClient.execute(packet2);
Для вывода информации по всем магазинам и всем книгам в магазине необходимо использовать Поиск DataSpace.
Предусмотрена сортировка коллекции объектов с помощью функции setSortingAdvanced. Для сортировки используются лямбды с суффиксом Picker (ниже пример сортировки по названию магазина в лексикографическом порядке по возрастанию).
//
BookStoreCollectionWith bookStoresCollectionWith = GraphCreator.selectBookStore()
.withName().withAddress()
.setSortingAdvanced(sort -> sort
.asc(fieldPicker -> fieldPicker.name())); // сортировка по названию магазина (по возрастанию)
// Запуск поиска
GraphCollection<BookStoreGet> bookStores = dataspaceCoreSearchClient.searchBookStore(bookStoresCollectionWith);
7.3. Поиск по связанным сущностям#
Тестовая функция createThirdBookStoreWithAnyBooks создает набор тестовых сущностей, в том числе экземпляров идентичных книг, распределенных по разным магазинам.
Особый интерес представляет поиск уникальных объектов. Для этого необходимо использовать метод с префиксом get.
BookStoreGet bookStoreBiblioGet =
dataspaceCoreSearchClient.getBookStore(spec -> spec.setWhere(bookStoreGrasp -> bookStoreGrasp.nameLike("Библио-Глобус%")));
Внимание!
Если по заданному условию будет найдено более одного элемента (например, если по запросу "Библио%" будут найдены магазины "Библио-Шар" и "Библиостар"), по запросу вернется исключение:
sbp.sbt.sdk.exception.detailedexception.TooManyResultsException: Найдено больше одной сущности.
7.4. Вывод всех объектов одного типа#
Тестовая функция searchAllBooksInAllBookStores создает коллекцию со свойствами всех книг, в том числе со свойствами всех связанных магазинов.
Особое внимание следует обратить на функцию setTotalCount, которая выводит общее число книг в связанном магазине.
BookCollectionWith bookCollectionWith = GraphCreator.selectBook()
.withName().withAuthor()
.withBookStore(bstWith -> bstWith
.withName().withAddress()
.withBooks(cw -> cw.setTotalCount(true)) // общее количество книг в магазине
)
.setSortingAdvanced(sort -> sort
.desc(fieldPicker -> fieldPicker.bookStore().booksCount())
.asc(BookGrasp::author).asc(BookGrasp::name)
.asc(fieldPicker -> fieldPicker.bookStore().name())
);
// Запустить поиск и получить как результат коллекцию
GraphCollection<BookGet> bookGets = dataspaceCoreSearchClient.searchBook(bookCollectionWith);
7.5. Изменение свойств объекта#
В начале функции searchByMaskAndUpdateAddressForBookStore производится поиск магазинов по адресу.
GraphCollection<BookStoreGet> bookStoresCollection =
dataspaceCoreSearchClient.searchBookStore(GraphCreator.selectBookStore()
.setWhere(bookStoreGrasp -> bookStoreGrasp.addressLike("Владимирский пр., 23, Санкт-Петербург%")));
Найденная коллекция магазинов обрабатывается в цикле: адрес каждого найденного магазина изменяется на новый. Для каждого магазина используется отдельный пакет. Для изменения свойств объекта необходимо использовать метод с суффиксом set.
for (int i = 0; i < bookStoresCollection.size(); ++i) {
BookStoreRef bookStoreRef = BookStoreRef.of(bookStoresCollection.get(i).getObjectId());
Packet updatingPacket = new Packet();
updatingPacket.bookStore.update(bookStoreRef, bookstore -> {
bookstore.setAddress("Невский пр., 28, Санкт-Петербург");
});
BookStoreGet bookStore = updatingPacket.bookStore.get(bookStoreRef, bookstore -> {
bookstore.withAddress();
bookstore.withName();
});
dataspaceCorePacketClient.execute(updatingPacket);
}
7.6. Проверка идемпотентности вызовов#
Идемпотентность — свойство вызовов, благодаря которому состояние агрегата не изменится при повторном идентичном вызове. Пример использования:
Микросервис создал книгу, но не успел вернуть результат.
Повторная команда создания этой книги не создаст дубликат книги, но вернет результат предыдущей исполненной команды.
В начале функции createBookWithIdempotence производится поиска магазина по названию.
Чтобы использовать идемпотентность для пакета, необходимо указать уникальный строчный ключ идемпотентности:
Packet creatingPacketWithIdempotence = Packet.builder().withIdempotencePacketId("CREATE STORE2 BookIdemp Непобедимый").build();
Внутри пакета создается объект:
BookRef bookRef = creatingPacketWithIdempotence.book.create(book -> {
book.setAuthor("Станислав Лем");
book.setName("Непобедимый");
book.setIsbn("978-5-17-060385-5");
book.setBookStore(biblioGlobusBookStoreRef);
});
После повторной попытки создания идентичного объекта из этого же пакета идентификатор объекта для первой переменной сравнивается с идентификатором второй переменной. Если идентификаторы совпали, дубликат объекта не был создан.
Assertions.assertEquals(bookRef.getId(), retryBookRef.getId());
7.7. Оптимистическая блокировка при обновлении объекта#
Оптимистическая блокировка не позволяет произвести изменения в агрегате, если между операциями чтения и записи он был изменен.
Рассмотрим тест подробнее.
Сначала выполняется поиск книги:
BookGet bookSearchByIsbn =
dataspaceCoreSearchClient.getBook(spec ->
spec.setWhere(bookGrasp ->
bookGrasp.isbnLike("978-5-17-060385-5%").
and(bookGrasp.bookStore().nameLike("Библио-Глобус%"))
)
);
BookRef bookRef = BookRef.of(bookSearchByIsbn.getObjectId());
После этого создается пакет с запросом версии агрегата (withAggregateVersionRequest), в котором вычитываются атрибуты и версия агрегата:
Packet readingPacketWithAggregateVersionRequest = Packet.builder().withAggregateVersionRequest().build();
BookGet bookGet = readingPacketWithAggregateVersionRequest.book.get(bookRef, book -> {
book.withName();
book.withAuthor();
book.withIsbn();
book.withBookStore(BookStoreWith::withName
);
});
После вычитки версии агрегат обновляется с повторной вычиткой версии агрегата:
Packet updatingPacket = Packet.builder().withAggregateVersion(3).build();
updatingPacket.book.update(BookRef.of(bookGet.getObjectId()), book -> {
book.setAuthor("Лем Станислав");
});
В конце метода фактическая версия агрегата проверяется на соответствие расчетной:
Assertions.assertEquals(4, readingPacketWithAggregateVersionRequestAfterUpdate.getAggregateVersion() );
Если между операцией вычитки агрегата с версией и обновлением агрегат будет изменен, то будет выдана ошибка следующего вида:
sbp.sbt.sdk.exception.detailedexception.AggregateVersionException:
Version 3 required but found 4 for object 6971773913230540804#ru.test.jpa.BookStore
Часть 8: Локальный запуск DataSpace#
Имеется возможность поднять сервис dataspace-core с соответствующей проекту моделью (model.xml) локально непосредственно на компьютере разработчика. Для этого после успешной сборки проекта из папки /model-local-test/local-run/ необходимо запустить скрипт:
./local-run.sh
В данном случае по адресу http://localhost:8080 будет запущен сервис dataspace-core.
Работоспособность, например, можно проверить при помощи графического GraphQL-интерфейса в веб-браузере, доступного по адресу http://localhost:8080/graphiql.
Более детально про возможности GraphQL-запросов DataSpace см. в документе "Протокол GraphQL".
Внимание!
После успешного локального запуска сервиса можно "проигрывать" демонстрационные тесты без необходимости длительного автоматического запуска сервиса dataspace-core "под капотом" теста. Для этого необходимо в файле model-local-test/src/test/java/ru/test/BaseTest.java закомментировать аннотацию
@ExtendWith({JUnit5DataSpaceCoreLocalRunnerExtension.class})и для атрибутаservicePortуказать соответствующий порт ранее поднятого локально сервиса (по умолчанию: 8080).
Демонстрационные материалы#
Пример включает в себя модель классов BookStore и Book. Вспомогательные материалы можно найти в ресурсах документа:
Возможные ошибки#
Ошибка при загрузке зависимостей#
Если необходимые зависимости были получены не архивом, а скачиваются из корпоративного хранилища, то может возникнуть следующая ошибка:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
В качестве постоянного решения можно настроить сертификаты в keystore, но это потребует некоторого времени на настройку.
В качестве быстрого решения можно добавить следующие параметры в команду сборки: -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true
Если вы используете Intellij IDEA, то можно добавить данные параметры в настройки, чтобы не вводить их вручную:
Откройте Preferences -> Build, Execution, Deployment -> Build Tools -> Maven -> Runner.
Введите в VM Options:
-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true.
Обычно после осуществления данных действий зависимости загружаются. Если описанные действия не помогли, то дополнительно проделайте следующее действие: File -> Invalidate Caches / Restart -> Invalidate and Restart.