java.lang.RuntimeException: wXb6Vnl31u :: Ошибка для HTML= 001 003 004 005 006 007 008 009
010

Как настроить входящую миграцию через 011 PostgreSQL с нуля

012 013

В этой статье вы прочитаете вначале общую концепцию входящей 014 миграции, потом общий алгоритм настройке входящей миграции, а потом 015 каждый пункт входящей миграции будет расписан детально.

016 017

Общая концепция миграции

018 019
    020
  1. Нужно в сторонней PostgreSQL БД создать таблицы нужного 021 формата.
  2. 022 023
  3. Потом в них будет сторонняя система заливать данные.
  4. 024 025
  5. После заливки она будет отмечать завершение заливки удалением 026 записи в специальной маркерной таблицы.
  6. 027 028
  7. После этот будет запускаться миграция, по окончанию которой 029 данные будут залиты на платформу.
  8. 030
031 032

Что нужно знать, чтобы пользоваться этим 033 руководством

034 035
    036
  1. Где находится директория логирования
  2. 037 038
  3. Где находятся файлы конфигурации
  4. 039
040 041

Алгоритм настройки

042 043

Для настройки входящей миграции через PostgreSQL необходимо 044 выполнить следующие пункты:

045 046
    047
  1. Отметить поля в бизнес-объектах, которые нужно мигрировать 048 из-вне на платформе MyBPM;
  2. 049 050
  3. Подключиться к сторонней базе-данных типа PostgreSQL например с 051 помощью pgAdmin - далее будем это БД называть импортной БД;
  4. 052 053
  5. Получить DDL-таблиц из платформы MyBPM;
  6. 054 055
  7. Накатить полеченные DDL-ы в импортной БД;
  8. 056 057
  9. Настроить подключение платформы MyBPM к импортной БД;
  10. 058 059
  11. Активировать миграцию и провести холостой пуск;
  12. 060 061
  13. Загрузить данные и смотреть процесс миграции;
  14. 062
063 064

Пункт 1. Отметить поля в бизнес-объектах

065 066

Давайте в качестве примера создадим простейший набор 067 бизнес-объектов, в котором будут все возможные сочетания полей.

068 069

Бизнес-объекты создаются в режиме редактирования нажатием на 070 кнопку с плюсом и выбором пункта "Бизнес-объект" как показано на 071 картинке:

072 073

pic001.png

074 075

Давайте создадим бизнес-объект "Физическое лицо" как показано на 076 картинке:

077 078

pic001.png

079 080

И укажем ему код: NaturalPerson как показано на 081 картинке:

082 083

pic002.png

084 085

Теперь зададим код Surname для поля 086 Фамилия как показано на картинке:

087 088

pic003.png

089 090

pic004.png

091 092

Остальные поля также, в итоге должно получиться два 093 бизнес-объекта с такими полями:

094 095
096  Бизнес-объект "Физическое лицо" с кодом "NaturalPerson"
097  И полями:  Фамилия        с кодом Surname       тип "Текстовое поле"
098             Имя            с кодом Name          тип "Текстовое поле"
099             ИИН            с кодом IIN           тип "Текстовое поле"
100             Дата рождения  с кодом BirthDate     тип "Дата"
101  
102  Бизнес-объект "Юридическое лицо" с кодом "LegalPerson"
103  И полями:  Имя            с кодом Name          тип "Текстовое поле"
104             БИН            с кодом BIN           тип "Текстовое поле"
105             Дата создания  с кодом CreateDate    тип "Дата"
106  
107  
108  
109  
110 111

Теперь создадим составной бизнес-объект, как показано на 112 картинке:

113 114

pic006.png

115 116

Выберем для его формирования бизнес-объекты Физическое и 117 Юридическое лица, как показано на рисунке:

118 119

pic007.png

120 121

Сформируем поля этого составного объекта-как показано на 122 рисунке:

123 124

pic008.png

125 126

Так же необходимо задать коды.

127 128

Должен получиться такой составной бизнес-объект:

129 130
131  Состановй бизнес-объект: "ЦО Клиент" с кодом "Client"
132  С полями:   "Дата рожд./созд." с кодом "CrDate"  связанный с полями: "Дата рождения" и "Дата создания"
133              "ИИН/БИН"          с кодом "BIIN"    связанный с полями: "ИИН" и "БИН"
134              "Имя"              с кодом "Name"    связанный с полями: "Имя" и "Имя"
135  
136  
137  
138  
139 140

Создадим ещё бизнес-объект "Заявка на клиента" (стрелочкой 141 обозначен перенос мышкой):

142 143

009.png

144 145

И создадим последний бизнес объект "Заявка на физическое лицо" 146 (стрелочкой обозначен перенос мышкой):

147 148

010.png

149 150

Теперь давайте перечислим всю созданную структуру 151 бизнес-объектов:

152 153
154  Бизнес-объект "Физическое лицо" с кодом "NaturalPerson"
155  И полями:  Фамилия        с кодом Surname       тип "Текстовое поле"
156             Имя            с кодом Name          тип "Текстовое поле"
157             ИИН            с кодом IIN           тип "Текстовое поле"
158             Дата рождения  с кодом BirthDate     тип "Дата"
159  
160  
161  
162 163

 

164 165
166  Бизнес-объект "Юридическое лицо" с кодом "LegalPerson"
167  И полями:  Имя            с кодом Name          тип "Текстовое поле"
168             БИН            с кодом BIN           тип "Текстовое поле"
169             Дата создания  с кодом CreateDate    тип "Дата"
170  
171  
172  
173 174

 

175 176
177  Составной бизнес-объект: "ЦО Клиент" с кодом "Client"
178  С полями:   "Дата рожд./созд." с кодом "CrDate"  связанный с полями: "Дата рождения" и "Дата создания"
179              "ИИН/БИН"          с кодом "BIIN"    связанный с полями: "ИИН" и "БИН"
180              "Имя"              с кодом "Name"    связанный с полями: "Имя" и "Имя"
181  
182  
183  
184 185

 

186 187
188  Бизнес-объект "Заявка на клиента" с кодом "ClientClaim"
189  И полями:  Название       с кодом Name          тип "Текстовое поле"
190             Описание       с кодом Descr         тип "Текстовый блок"
191             ЦО Клиент      с кодом CoClient      ссылается на ЦО "ЦО Клиент"
192  
193  
194  
195 196

 

197 198
199  Бизнес-объект "Заявка на физическое лицо" с кодом "NaturalClaim"
200  И полями:  Наименование     с кодом Name          тип "Текстовое поле"
201             Описание         с кодом Descr         тип "Текстовый блок"
202             Физическое лицо  с кодом Natural       ссылается на БО "Физическое лицо"
203  
204  
205  
206  
207 208

Теперь все поля этих бизнес объектов необходимо отметить, что 209 они участвуют в in-migration как показано на рисунке:

210 211

011.png

212 213

Это нужно сделать для всех полей простых бизнес-объектов. Для 214 составных бизнес-объектов это делать не нужно, так как в составном 215 бизнес-объекте данны нет - они распределены по составляющим этого 216 БО.

217 218

Не забывайте сохранять изменённые данные.

219 220

Пункт 2. Подключение к сторонней БД 221 PostgreSQL

222 223

Описание этого пункта не входит в обязанность данного 224 руководства. Вам необходимо заранее ознакомиться с подобными 225 руководствами.

226 227

Единственное отметим, что для подключения необходимо знать 228 следующие параметры:

229 230
    231
  1. Хост или IP-адрес сервера базы данных, на котором размещена БД. 232 Например: 192.168.32.31 - это IP-адрес, или db01.mybpm.local
  2. 233 234
  3. Порт подключения - это число например 5432
  4. 235 236
  5. Имя базы данных - например mybpm_out
  6. 237 238
  7. Имя схемы в базе данных - например in_tables
  8. 239 240
  9. Имя пользователя - например mybpm
  10. 241 242
  11. Пароль пользователя - например 6dfxHTESrO
  12. 243
244 245

Эти данные необходимо получить от администратора баз данных. 246 Дальше их ввести в pgAdmin-е при создании подключения, и, если 247 подключение будет успешно, то они правильные.

248 249

Дальше по тексту мы будет пользоваться следующими 250 значениями:

251 252
253  IP-адрес сервера базы данных = 192.168.11.23
254  Порт подключения             = 10018
255  Имя базы данных              = migration
256  Имя схемы в базе данных      = in_tables
257  Имя пользователя             = mybpm_migration
258  Пароль пользователя          = 6dfxHTESrO
259  
260  
261  
262  
263 264

Пункт 3. Получить DDL-таблиц из платформы 265 MyBPM

266 267

В начале в конфиге нужно прописать схему базы данных. Для этого 268 откройте конфиг

269 270
271  /mybpm/configs/InMigrationPostgresConfig.txt
272  
273  
274  
275  
276 277

И в нём укажите схему базы данных, в которой будут помещены 278 таблицы для миграции:

279 280

012.png

281 282

Теперь можно получить DDL-для создания входящих таблиц. Для 283 этого нужно выполнить Rest-запрос:

284 285
286  GET http://localhost:1313/web/migration/generate-in-ddl?companyCode=greetgo
287  
288  
289  
290  
291 292

Здесь вместо greetgo вам необходимо указать код 293 того аккаунта, в котором вы создали бизнес-объекты.

294 295

А вместо http://localhost:1313 нужно указать адрес 296 установленной платформы MyBPM.

297 298

Вот пример как это сделано в Postman-е:

299 300

013.png

301 302

На выходе этого запроса получиться список команд create 303 table ..., в которых будут созданы все необходимые таблицы, 304 через которые будет происходить миграция.

305 306

Пункт 4. Накатить полеченные DDL-ы в импортной 307 БД

308 309

Эти DDL-и нужно применить для импортной базы данных, чтобы в ней 310 все эти таблицы появились. Вот пример как это сделано в 311 DataGrip:

312 313

014.png

314 315

Сгенерировались следующие таблицы:

316 317
318  in_naturalperson - данные простых полей NaturalPerson
319  in_legalperson   - данные простых полей LegalPerson
320  in_naturalclaim  - данные простых полей NaturalClaim
321  in_clientclaim   - данные простых полей ClientClaim
322  in_naturalclaim_natural - связка NaturalClaim через поле NaturalClaim.Natural на бизнес-объект NaturalClaim
323  in_clientclaim_coclient_neturalperson - связка ClientClaim через поле ClientClaim.CoClient на бизнес-объект NaturalPerson
324  in_clientclaim_coclient_legalperson   - связка ClientClaim через поле ClientClaim.CoClient на бизнес-объект LegalPerson
325  in_filestorage - файлы для полей с файлами
326  process_tracking - индикация начала запуска
327  
328  
329  
330  
331 332

Пункт 5. Настроить подключение платформы MyBPM к 333 импортной БД;

334 335

Настройка подключения к импортной БД осуществляется в 336 конфиге:

337 338
339  /mybpm/configs/InMigrationPostgresConfig.txt
340  
341  
342  
343  
344 345

Там ранее уже прописали параметр schemaName. Теперь 346 нужно остальные прописать.

347 348
349  host=192.168.11.23
350  port=10018
351  dbName=migration
352  username=mybpm_migration
353  password=6dfxHTESrO
354  schemaName=in_tables
355  hasInMigration=true
356  
357  
358  
359  
360 361

В данном случае пароль и имя пользователя прописаны в открытом 362 виде. Если это недопустимо, то можно определить переменные 363 окружения, например такие:

364 365
366  IN_MIGRATION_DATABASE=migration
367  IN_MIGRATION_USERNAME=mybpm_migration
368  IN_MIGRATION_PASSWORD=6dfxHTESrO
369  
370  
371  
372  
373 374

И теперь прописать в конфиге 375 /mybpm/configs/InMigrationPostgresConfig.txt ссылки на 376 эти переменные окружения:

377 378
379  host=192.168.11.23
380  port=10018
381  dbName:ENV=IN_MIGRATION_DATABASE
382  username:ENV=IN_MIGRATION_USERNAME
383  password:ENV=IN_MIGRATION_PASSWORD
384  schemaName=in_tables
385  hasInMigration=true
386  
387  
388  
389  
390 391

В результате у конфигурационном файле нет отрытых паролей.

392 393

Пункт 6. Активировать миграцию и провести холостой 394 пуск

395 396

Теперь давайте активируем миграцию и проведём холостой пуск, 397 т.е. пуск на пустые таблицы, чтобы убедиться, что всё работает.

398 399

Информация о миграции кидается в категорию 400 inMigration.

401 402

Вначале настроим информационный журнал миграции. Для этого 403 необходимо зайти в конфиг настройки журналирования:

404 405
406  /mybpm/logging/structure.txt
407  
408  
409  
410  
411 412

В этом файле найти запись (примечание, в редакторе 413 ZooNavigator-а есть горячая кнопа Ctrl+H для поиска)

414 415
416  category inMigration
417      level INFO
418      assign_to in_migration
419  
420  
421  
422  
423 424

Эта категория отфильтровывает логи до уровня INFO и отсылает их 425 к приёмнику in_migration. Посмотрим на этот приёмник. 426 В этом же файле нужно найти запись.

427 428
429  destination in_migration
430      destination in_migration to_file migration/in_migration
431      level INFO
432  
433  
434  
435  
436 437

Как видим этот приёмник кладёт логи в файл 438 migration/in_migration.log. Найдём этот файл и будем 439 за ним наблюдать.

440 441
442

Миграция активируется в двух местах: активация факта миграции, 443 расписание запуска миграции, таблица 444 in_table.process_tracking

445 446

Сам факт миграции активируется в конфигурационном файле:

447 448
449  /mybpm/configs/InMigrationPostgresConfig.txt
450  
451  
452  
453  
454 455

В параметре:

456 457
458  hasInMigration=true
459  
460  
461  
462  
463 464

Ранее мы уже его поставили в состояние true, т.е. 465 миграция активирована. Проверьте это на всякий случай.

466 467
468

Чтобы миграция запускалась необходимо, чтобы таблица 469 in_table.process_tracking была пустой. Так как мы её 470 только что создали, то она должна быть пустой. Проверьте это. Если 471 там есть запись, то удалите её.

472 473

Запись в этой таблице показывает, что миграция уже отработала 474 или ещё работает, и повторную миграцию запускать не нужно.

475 476
477

Теперь нужно настроить расписание запуска миграции. Оно 478 находиться в конфигурационном файле:

479 480
481  /mybpm/scheduler/core/InMigrationScheduler.scheduler-config.txt
482  
483  
484  
485  
486 487

В параметре:

488 489
490  startMigrate = repeat every 1 minute
491  
492  
493  
494  
495 496

Давайте сделаем чтобы инициация запуска миграции происходила 497 каждую минуту. Не беспокойтесь, параллельно вторая миграция не 498 запуститься, так как это не даст таблица 499 in_table.process_tracking. При запуске миграции в ней 500 появляется запись, которая блокирует последующий запуск миграции 501 параллельно.

502 503

Дальше смотрим ранее указанный лог. Там в течении минуты должны 504 появиться записи. Если там появилась ошибка

505 506
507  java.lang.RuntimeException: nYz1en475t :: config.hasInMigration() = true
508  
509  
510  
511  
512 513

То нужно перезапустить сервер. Изменения в конфиге не 514 применились.

515 516

При старте сервера может вылететь ошибка:

517 518
519  Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "mybpm_migration"
520  
521  
522  
523  
524 525

Это обозначает что система не смогла подключиться к базе данных. 526 Проверьте правильность параметров в конфиге:

527 528
529  /mybpm/configs/InMigrationPostgresConfig.txt
530  
531  
532  
533  
534 535

И запустите сервер mybpm-api заново.

536 537

Если сервер запустился, значит доступ к БД настроен верно.

538 539

Вот нормальный лог миграции:

540 541
542  2024-12-26T08:59:33.261 INFO  Q inMigration g5mP3u7hF4 :: cleanErrorsTable start
543  2024-12-26T08:59:33.264 INFO  Q inMigration mX9xgIdrQt :: clean days = 10, limit = 10000
544  2024-12-26T08:59:33.268 INFO  Q inMigration vhhSIlN1W5 :: started saving data to kafka
545  2024-12-26T08:59:33.269 INFO  Q inMigration 1RHJ7aF2vu :: errors cleaner deleted 0rows in 6 ms.
546  2024-12-26T08:59:33.285 INFO  Q inMigration w7qP9r57 :: start migration to Kafka by companyId=6f27ebce5e49a79d69e522a8
547  2024-12-26T08:59:33.290 INFO  Q inMigration 27TtdVdLGj :: periodic_update_time updated
548  2024-12-26T08:59:33.298 INFO  Q inMigration uENuePJ3M1 :: start to vacuum system tables
549  2024-12-26T08:59:33.347 INFO  Q inMigration uENuePJ3M1 :: finish to vacuum system tables
550  2024-12-26T08:59:33.440 INFO  Q inMigration 7cUnbAdw29 :: in migration worker returned boStructure as null for Аккаунт
551  2024-12-26T08:59:33.445 INFO  Q inMigration 7cUnbAdw29 :: in migration worker returned boStructure as null for Пользователи
552  2024-12-26T08:59:33.448 INFO  Q inMigration 7cUnbAdw29 :: in migration worker returned boStructure as null for Департамент
553  2024-12-26T08:59:33.450 INFO  Q inMigration 7cUnbAdw29 :: in migration worker returned boStructure as null for Рабочая группа
554  2024-12-26T08:59:33.465 INFO  Q inMigration uAhZ1PFqMe :: copyInTableData start
555  2024-12-26T08:59:33.469 INFO  Q inMigration Gf4MsN7oi5 :: copyInTableData for table = in_NaturalPerson start
556  2024-12-26T08:59:33.479 INFO  Q inMigration 6ri5uiI970 :: copy table with name copy_2024_12_26_in_NaturalPerson is already exists, will be skipped
557  2024-12-26T08:59:33.479 INFO  Q inMigration 9o0WErV28h :: copyInTableData for table = in_NaturalPerson finish
558  2024-12-26T08:59:33.479 INFO  Q inMigration XvCndCKLGg :: extra table is empty, so no copy table will be created for extra
559  2024-12-26T08:59:33.480 INFO  Q inMigration AI0KjWef :: start setting status ON_WORK to in_tables.in_NaturalPerson occupied_id=612308124825686351
560  2024-12-26T08:59:33.489 INFO  Q inMigration CHWarE4y :: finish setting status ON_WORK to in_tables.in_NaturalPerson occupied_id=612308124825686351
561  2024-12-26T08:59:33.496 INFO  Q inMigration uAhZ1PFqMe :: copyInTableData start
562  2024-12-26T08:59:33.497 INFO  Q inMigration Gf4MsN7oi5 :: copyInTableData for table = in_LegalPerson start
563  2024-12-26T08:59:33.497 INFO  Q inMigration 6ri5uiI970 :: copy table with name copy_2024_12_26_in_LegalPerson is already exists, will be skipped
564  2024-12-26T08:59:33.497 INFO  Q inMigration 9o0WErV28h :: copyInTableData for table = in_LegalPerson finish
565  2024-12-26T08:59:33.497 INFO  Q inMigration XvCndCKLGg :: extra table is empty, so no copy table will be created for extra
566  2024-12-26T08:59:33.497 INFO  Q inMigration AI0KjWef :: start setting status ON_WORK to in_tables.in_LegalPerson occupied_id=612308124825686351
567  2024-12-26T08:59:33.502 INFO  Q inMigration CHWarE4y :: finish setting status ON_WORK to in_tables.in_LegalPerson occupied_id=612308124825686351
568  2024-12-26T08:59:33.505 INFO  Q inMigration 7cUnbAdw29 :: in migration worker returned boStructure as null for ЦО Клиент
569  2024-12-26T08:59:33.511 INFO  Q inMigration uAhZ1PFqMe :: copyInTableData start
570  
571  
572  
573  
574 575

При запуске миграции, в таблице:

576 577
578  in_table.process_tracking
579  
580  
581  
582  
583 584

Появиться одна запись, которая будет блокировать дальнейшие 585 запуски миграции.

586 587

Пункт 7. Загрузить данные и смотреть процесс 588 миграции

589 590

Теперь можно заполнять эти таблицы данными.

591 592

После заполнения этих таблиц нужно удалить запись в таблице 593 in_table.process_tracking и миграция запуститься в 594 течении минуты.

595 596

Есть в базе данных mybpm_aux1 таблица:

597 598
599  in_migration.log
600  
601  
602  
603  
604 605

В которую выбрасываются ошибки миграции.

606 607

Есть таблица:

608 609
610  in_migration.timings
611  
612  
613  
614  
615 616

В которой отображается скорость миграции. Какие таблицы и 617 сколько про-мигрировал-ись.

618
619 620 at kz.greetgo.md_reader.util.MdUtil.xmlTextToDoc(MdUtil.java:80) at kz.greetgo.md_reader.core.MdConverter.prepareHtmlFileFrom(MdConverter.java:136) at kz.greetgo.md_reader.core.MdConverter.convert(MdConverter.java:208) at kz.greetgo.md_reader.controller.RenderController.downloadToc(RenderController.java:360) at kz.greetgo.md_reader.controller.RenderController.request(RenderController.java:108) at jdk.internal.reflect.GeneratedMethodAccessor3.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at kz.greetgo.md_reader.interceptors.TextReplaceFilter.doFilter(TextReplaceFilter.java:36) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: java.io.IOException: Server returned HTTP response code: 429 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2000) at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:677) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1397) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1333) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.startPE(XMLDTDScannerImpl.java:732) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.skipSeparator(XMLDTDScannerImpl.java:2101) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.scanDecls(XMLDTDScannerImpl.java:2064) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.scanDTDExternalSubset(XMLDTDScannerImpl.java:299) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1165) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1040) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:943) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:542) at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:889) at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:825) at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:247) at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:342) at java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122) at kz.greetgo.md_reader.util.MdUtil.xmlTextToDoc(MdUtil.java:71) ... 48 more