LINUX.ORG.RU

Сообщения popov-aa

 

Как перестать пугать коллег посторонними звуками во время созвонов?

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

Пытался себя приучить ставить микрофон на mute, но безуспешно.

Посоветуйте микрофон, который можно установить на подставку или кронштейн, с физической кнопкой включения звука.

В магазинах куча предложений микрофонов с кнопками, но у всех них кнопка работает как переключатель. Ее я тоже буду забывать нажимать. Необходим принцип работы как у рации - пока ты держишь кнопку, звук есть, как только отпустил, звук выключился.

Есть ли такое в природе?

 

popov-aa
()

Проблема с потоковым воспроизведением в QMediaPlayer

Добрый день. Имеется приложение на Qt, которому стримят на udp порт видео следующего формата:

General
Complete name                            : cam7.avi
Format                                   : AVI
Format/Info                              : Audio Video Interleave
File size                                : 767 MiB
Duration                                 : 12 min 0 s
Overall bit rate                         : 8 927 kb/s
Writing application                      : MEncoder Redxii-SVN-r37313-4.8.3
Writing library                          : MPlayer

Video
ID                                       : 0
Format                                   : JPEG
Codec ID                                 : IJPG
Codec ID/Hint                            : Intergraph
Duration                                 : 12 min 0 s
Bit rate                                 : 8 922 kb/s
Width                                    : 1 280 pixels
Height                                   : 720 pixels
Display aspect ratio                     : 16:9
Frame rate                               : 25.000 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Compression mode                         : Lossy
Bits/(Pixel*Frame)                       : 0.387
Stream size                              : 766 MiB (100%)

Стоит задача отображать его в osgEarth. Начать я решил с получения очередного кадра посредством QAbstractVideoSurface, накидал небольшой тест: https://github.com/popov-aa/MJpegStream.git

Параметр запуска –input определяет источник воспроизведения: file - посредством установки setMedia «file://», stream - устанавливает конвейер gstreamer, содержащий udpsrc:

gst-pipeline: udpsrc port=20101 ! application/x-rtp,encoding-name=JPEG,payload=26 ! rtpjpegdepay ! jpegdec ! xvimagesink name=qtvideosink

Параметр запуска –output определяет куда будет выводится видео: widget - в QVideoWidget, surface - в QLabel посредством QAbstractVideoSurface.

Результаты следующие (параметры запуска):

–input file –output widget Отображение в QVideoWidget корректное, дополнительных окон нет

–input file –output surface Отображение в Surface widget корректное, дополнительных окон нет

Это говорит о том, что с кодеками в системе все хорошо, MyVideoSurface корректно извлекает каждый кадр.

–input stream –output widget QVideoWidget - черный, отображение видео в другом окне

–input stream –output surface Surface widget - пустой, отображение видео в другом окне

А вот распознание потока уже хромает. Воспроизведение потока запускаю следующим способом:

gst-launch-1.0 -v filesrc location=cam7.avi ! avidemux ! rtpjpegpay ! udpsink host=127.0.0.1 port=20101

Оригинальное видео, на котором я тестирую, к сожалению не могу залить. Заменил его бажным сгенерированным куском, но поведение теста от этого не изменилось.

Подозреваю, что проблема в конвейере gstreamer, но пока не понял где. Однако при этом поток воспроизводится в отдельном окне, то есть все успешно декодируется. Прошу помощи у сообщества. Залитый на github тест самодостаточный, содержит примерное видео.

 ,

popov-aa
()

Не применяется профиль к LXD контейнеру

Добрый день. На рабочей машине под управлением Kubuntu я настроил проброс X11 из контейнера на хост по этой статье: https://blog.simos.info/running-x11-software-in-lxd-containers/ В убунте с LXD вообще минимум головняка. Все свелось к созданию и назначению контейнеру профиля следующего содержания:

config:
  environment.DISPLAY: :0
  nvidia.driver.capabilities: all
  nvidia.runtime: "true"
  user.user-data: |
    packages:
      - x11-apps
      - mesa-utils
description: GUI LXD profile
devices:
  X0:
    bind: container
    connect: unix:@/tmp/.X11-unix/X0
    listen: unix:@/tmp/.X11-unix/X0
    security.gid: "1000"
    security.uid: "1000"
    type: proxy
  mygpu:
    type: gpu
Xauth:
    path: /home/popov-aa/.Xauthority
    source: /home/popov-aa/.Xauthority
    type: disk
name: x11
used_by: []

Решил повторить успех на домашней системе под управлением ArchLinux. Официальный гайд я выполнил частично, опустив настройку сети, но непривилегированные контейнеры настроены.

Суть проблемы сводится к тому, что под ArchLinux как будто не применяются профили.

[popov-aa@PopovDesktop ~]$ lxc profile show x11
config:
  environment.DISPLAY: :0
  nvidia.driver.capabilities: all
  nvidia.runtime: "true"
  user.user-data: |
    packages:
      - x11-apps
      - mesa-utils
description: GUI LXD profile
devices:
  X0:
    bind: container
    connect: unix:@/tmp/.X11-unix/X0
    listen: unix:@/tmp/.X11-unix/X0
    security.gid: "1000"
    security.uid: "1000"
    type: proxy
  mygpu:
    type: gpu
name: x11
used_by:
- /1.0/instances/centos7-ians
- /1.0/instances/mycontainer
- /1.0/instances/centos7-ians-test
[popov-aa@PopovDesktop ~]$ lxc config device show centos7-ians-test
{}
[popov-aa@PopovDesktop ~]$

[popov-aa@centos7-ians-test ~]$ ls /tmp/.X11-unix/X0
ls: cannot access /tmp/.X11-unix/X0: No such file or directory
[popov-aa@centos7-ians-test ~]$ glxgears 
No protocol specified
Error: couldn't open display :0
[popov-aa@centos7-ians-test ~]$

В чем может быть проблема?

 , ,

popov-aa
()

No EntityManager with actual transaction available for current thread

Имеется приложение (spring-boot, spring-data-jpa) в одном из бинов которого я хочу создать с помощью EntityManager пару сущностей. В результате получаю исключение «No EntityManager with actual transaction available for current thread - cannot reliably process ‘persist’ call» при вызове persist. Сохранение через JpaRepository при этом работает корректно. Метод, в котором происходит вызов проаннотирован @Transactional. Не подскажите, с чем это может быть связано? Репозиторий: https://github.com/popov-aa/spring-boot-test

 , , ,

popov-aa
()

yoyo migrations не может развернуть БД на mysql

Столкнулся с тем, что yoyo migrations не может развернуть БД на mysql, в которой объявляются процедуры с REPEAT.

Допустим, мы хотим использовать чуть подчищенный вариат дампа произведенного с помощью mysqldump:

DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `yoyo_lock`;
CREATE TABLE `yoyo_lock` (
  `locked` int NOT NULL DEFAULT '1',
  `ctime` timestamp NULL DEFAULT NULL,
  `pid` int NOT NULL,
  PRIMARY KEY (`locked`)
) ENGINE=InnoDB;

DELIMITER ;;
CREATE DEFINER=`root`@`%` FUNCTION `test_function`() RETURNS int
    READS SQL DATA
    DETERMINISTIC
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
	return test_var;
end ;;

CREATE DEFINER=`root`@`%` PROCEDURE `test_procedure`()
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
end ;;
DELIMITER ;

Как видим, mysql его спокойно разворачивает:

[popov-aa@archlinux yoyo]$ mysql -u root -p -h 172.28.1.21 test_db < ./migrations/20200717_01_dHiTT-create-schema.sql 
Enter password: 
[popov-aa@archlinux yoyo]$ 

Теперь попробуем развернуть этот же дамп с помощью yoyo, получаем ошибку:

DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `yoyo_lock`;
CREATE TABLE `yoyo_lock` (
  `locked` int NOT NULL DEFAULT '1',
  `ctime` timestamp NULL DEFAULT NULL,
  `pid` int NOT NULL,
  PRIMARY KEY (`locked`)
) ENGINE=InnoDB;

CREATE DEFINER=`root`@`%` FUNCTION `test_function`() RETURNS int
    READS SQL DATA
    DETERMINISTIC
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
	return test_var;
end ;

CREATE DEFINER=`root`@`%` PROCEDURE `test_procedure`()
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
end ;
Получаем:
[popov-aa@archlinux yoyo]$ yoyo apply
/home/popov-aa/.local/lib/python3.8/site-packages/pymysql/cursors.py:170: Warning: (1051, "Unknown table 'test_db.test_table'")
  result = self._query(query)
Traceback (most recent call last):
...
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER' at line 1")
[popov-aa@archlinux yoyo]$ 
Модифицируем дамп, удалив DELIMITER:
[popov-aa@archlinux yoyo]$ yoyo apply
Traceback (most recent call last):
...
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 8")
[popov-aa@archlinux yoyo]$ 
При этом вариант без REPEAT проходит на ура:
DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `yoyo_lock`;
CREATE TABLE `yoyo_lock` (
  `locked` int NOT NULL DEFAULT '1',
  `ctime` timestamp NULL DEFAULT NULL,
  `pid` int NOT NULL,
  PRIMARY KEY (`locked`)
) ENGINE=InnoDB;

CREATE DEFINER=`root`@`%` FUNCTION `test_function`() RETURNS int
    READS SQL DATA
    DETERMINISTIC
begin
	declare test_var int default 1;
	return test_var;
end ;

CREATE DEFINER=`root`@`%` PROCEDURE `test_procedure`()
begin
	declare test_var int default 1;
end ;
[popov-aa@archlinux yoyo]$ yoyo apply
[popov-aa@archlinux yoyo]$ 
У кого-нибудь есть догадки в чем проблема и как быть?

 ,

popov-aa
()

Проблемы с checkinstall под Ubuntu 20.04

Пытаюсь собрать пакет qamqp с помощью checkinstall под Ubuntu 20.04. Беру исходники с github.com, выполняю qmake, make - никаких ошибок. На sudo checkinstall возникает следующая ошибка:

========================= Результаты установки ===========================
cd src/ && ( test -e Makefile || /usr/lib/qt5/bin/qmake -o Makefile /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/src.pro ) && make -f Makefile install
make[1]: вход в каталог «/home/popov/Mountpoints/SSD/Projects/C++/qamqp/src»
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpauthenticator.h /usr/include/qamqp/qamqpauthenticator.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpauthenticator.h to /usr/include/qamqp/qamqpauthenticator.h: Cannot create /usr/include/qamqp/qamqpauthenticator.h for output
make[1]: [Makefile:603: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpchannel.h /usr/include/qamqp/qamqpchannel.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpchannel.h to /usr/include/qamqp/qamqpchannel.h: Cannot create /usr/include/qamqp/qamqpchannel.h for output
make[1]: [Makefile:604: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpclient.h /usr/include/qamqp/qamqpclient.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpclient.h to /usr/include/qamqp/qamqpclient.h: Cannot create /usr/include/qamqp/qamqpclient.h for output
make[1]: [Makefile:605: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpexchange.h /usr/include/qamqp/qamqpexchange.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpexchange.h to /usr/include/qamqp/qamqpexchange.h: Cannot create /usr/include/qamqp/qamqpexchange.h for output
make[1]: [Makefile:606: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpglobal.h /usr/include/qamqp/qamqpglobal.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpglobal.h to /usr/include/qamqp/qamqpglobal.h: Cannot create /usr/include/qamqp/qamqpglobal.h for output
make[1]: [Makefile:607: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpmessage.h /usr/include/qamqp/qamqpmessage.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpmessage.h to /usr/include/qamqp/qamqpmessage.h: Cannot create /usr/include/qamqp/qamqpmessage.h for output
make[1]: [Makefile:608: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpqueue.h /usr/include/qamqp/qamqpqueue.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqpqueue.h to /usr/include/qamqp/qamqpqueue.h: Cannot create /usr/include/qamqp/qamqpqueue.h for output
make[1]: [Makefile:609: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqptable.h /usr/include/qamqp/qamqptable.h
Error copying /home/popov/Mountpoints/SSD/Projects/C++/qamqp/src/qamqptable.h to /usr/include/qamqp/qamqptable.h: Cannot create /usr/include/qamqp/qamqptable.h for output
make[1]: [Makefile:610: install_headers] Ошибка 3 (игнорирование)
/usr/lib/qt5/bin/qmake -install qinstall -exe libqamqp.so.0.5.0 /usr/lib/libqamqp.so.0.5.0
Error copying libqamqp.so.0.5.0 to /usr/lib/libqamqp.so.0.5.0: Cannot create /usr/lib/libqamqp.so.0.5.0 for output
make[1]: [Makefile:626: install_target] Ошибка 3 (игнорирование)
strip --strip-unneeded /usr/lib/libqamqp.so.0.5.0
strip: «/usr/lib/libqamqp.so.0.5.0»: Нет такого файла
make[1]: [Makefile:627: install_target] Ошибка 1 (игнорирование)
ln -f -s libqamqp.so.0.5.0 /usr/lib/libqamqp.so
ln -f -s libqamqp.so.0.5.0 /usr/lib/libqamqp.so.0
ln -f -s libqamqp.so.0.5.0 /usr/lib/libqamqp.so.0.5

При этом пакет собирается, но содержит далеко не все инсталлируемые файлы. Первое что бросается в глаза - отсутствие бинарников. Кто-нибудь сталкивался с подобным? Убунта дефолтная, сразу после установки. Полный вывод: https://pastebin.com/hZG6LATr

 ,

popov-aa
()

Резервирование docker

Добрый день, товарищи. На боевом сервере, что мне доверили, в docker-контейнерах крутится следующее: postgres, nginx, gitea, certbot, youtrack, registry, portainer и корпоративное приложение на java. Все контейнеры описаны в docker-compose, а все тома именованные. Насколько неправилен следующий алгоритм бэкапа:

  • Останавливаю docker, чтобы не велась запись в тома;
  • Тарболю /var/lib/docker/volumes/ вместе с docker-compose.yaml;
  • Запускаю docker;
  • Заливаю полученный тарбол на резервный сервер. В случае уничтожения основного сервера на резервном распаковываю в /var/lib/docker/volumes тома, запускаю docker-compose up. Насколько описанный способ самодостаточен, охватывает ли он все нюансы? Как я понимаю, вопрос резервирования в докере можно разбить на три части: резервирование образов, резервирование контейнеров и резервирование томов и все это можно делать встроенным средствами docker. Но резервировать образы я не вижу смысла, так как все они есть в docker hub. Смысл резервировать контейнеры тоже не ясен, так как я использую именованные тома и бэкаплю их. Бэкап томов средствами докера выглядит сложнее, чем банальный тарбол.

 

popov-aa
()

Однажды установленное jsonb поле не удается изменить

Имеется вебприложение на следующем стеке: backend: java 8, spring-boot, spring-mvc, hibernate, postgresql. frontend: reactjs, material-ui.

Возникла необходимость отображать яндекс-карту с метками. Я решил сохранять информацию, которую получаю от яндексовского сервиса в jsonb.

Сущность в которой необходимо сохранять инфу:

@NoArgsConstructor
@Getter @Setter
@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
@Entity
public class Location extends Identifiable implements Serializable {
    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private Geolocation geolocation;
}
https://pastebin.com/FX9XUxjg

Классы, являющиеся отражением структуры json:

@NoArgsConstructor
@Getter @Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@TypeDefs({
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
@MappedSuperclass
public class Geolocation {
    private Double latitude;
    private Double longitude;
    private Address address;
}
https://pastebin.com/dqDTeddD

@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@TypeDefs({
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
@MappedSuperclass
public class Address {
    private String countryCode;
    private String formatted;
    private String postalCode;
    private Map<String,String> components = new HashMap<>();
}

https://pastebin.com/3pVBBGGH

Метод контроллера, вызывающийся для сохранения геолокации:

@Log4j2
@Controller
@RequestMapping(value = "/api/locations")
public class LocationController {

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private LocationRepository locationRepository;

    @PreAuthorize("hasRole('ADMIN')")
    @Transactional
    @RequestMapping(value = "/{id}/geolocation", method = RequestMethod.POST)
    @ResponseBody
    public com.helan.videoafisha.dto.general.Location saveGeolocation(
            @PathVariable("id") Long id,
            @RequestBody com.helan.videoafisha.dto.backend.frontend.reactjs.locations.with_geolocation.Geolocation modelGeolocation) {
        Location location = locationRepository.getOne(id);
        Geolocation geolocation = modelMapper.map(modelGeolocation, Geolocation.class);
        location.setGeolocation(geolocation);
        locationRepository.save(location);
        return modelMapper.map(location, com.helan.videoafisha.dto.general.Location.class);
    }
}
https://pastebin.com/BbxWxpNH

Суть проблемы заключается в том, что когда geolocation равен null, тогда даный метод отрабатывает корректно: https://imgur.com/PE5lvKQ.png

Hibernate: 
    update
        backend.location 
    set
        geolocation=?,
        max_device_count=?,
        site_id=?,
        time_zone_id=?,
        title=? 
    where
        id=?
2020-04-01 16:42:31.339 DEBUG - c.h.v.b.m.l.LogRequestFilter             : 200 POST /api/locations/1/geolocation [member #1/admin@mail.ru] 127.0.0.1:41090 {"isRequesting":false,"latitude":55.69962195079022,"longitude":37.62218505859374,"address":{"countryCode":"RU","formatted":"Россия, Москва, Варшавское шоссе, 13с4","postalCode":"117105","components":{"country":"Россия","province":"Центральный федеральный округ","locality":"Москва","street":"Варшавское шоссе","house":"13с4"}}}
https://imgur.com/8mc7odJ.png

После этого, когда geolocation не null повторные вызовы с другими данными не приводят ни к каким изменениям. Даже update не вызывается. Отладка метода не выявила никаких иных условий выполнения.

2020-04-01 16:49:14.836 DEBUG - c.h.v.b.m.l.LogRequestFilter             : 200 POST /api/locations/1/geolocation [member #1/admin@mail.ru] 127.0.0.1:41202 {"isRequesting":false,"latitude":55.70117301801526,"longitude":37.58991271972656,"address":{"countryCode":"RU","formatted":"Россия, Москва, улица Вавилова, 9Ас17","postalCode":"117312","components":{"country":"Россия","province":"Центральный федеральный округ","locality":"Москва","street":"улица Вавилова","house":"9Ас17"}}}

Чем может быть вызвано подобное поведение? Если вручную установить колонку geolocation в null, то метод отработает как надо.

 , , , ,

popov-aa
()

nested containers в boost-di

В целях изучения Hypodermic перевел свой старый проект на Hypodermic. Всё было прекрасно, пока я не столкнулся с невозможностью использовать forward declaration для зависимостей, инжектируемых через конструктор для классов, порождаемых с помощью resolve.

Однако почти весь проект уже переведен на использование инъекций зависимостей и автосвязывания и не хотелось от этого отказываться.

Лишен ли этого недостатка boost-di? Если да, то подскажите как в нем реализовать аналог nested containers из Hypodermic и как получить в качестве зависимости контейнер, дабы вручную извлечь из него требуемую зависимость?

 

popov-aa
()

Рабочие столы в Gnome (Ubuntu 19)

После многих лет использования ArchLinux решил попробовать Ubuntu (19), и в качестве десктопа он мне очень даже понравился. Одна беда: рабочие столы почему-то расположены вертикально, а не горизонтально, как я привык и с хоткеями беда.

Большая часть расширений не работает, запустился только «Workspace Matrix», он смог разместить рабочие столы горизонтально. Но он не предоставляет возможности настроить хоткеи для переключения, а в стандартных настройках хоткеев доступно переключение рабочих столов только по вертикали.

Ctrl+Alt+Left/Right в продуктах JetBrains не работает, ибо захардкожено на управление рабочими столами. Помогите решить данные проблемы.

Резюмирую, что мне нужно: 1) Чтобы рабочих столов было 4 по горизонтали; 2) Чтобы переключаться между ними можно было по Alt+A (предыдущий), Alt+D (следующий) с враппингом; 3) Чтобы в Idea и Webstorm работали хоткеи Alt+Ctrl+Left/Right.

 

popov-aa
()

Ошибка в тесте geekbrains?

Пришла пора менять работу. Решил попроходить различные тесты, чтобы выявить пробелы в знаниях и устранить их. Попутно заинтересовался курсами в geekbrains, потому их тесты стал проходить первыми.

Вопрос из группы сложных: https://i.imgur.com/KOMTtok.png

Так как цикл do-while, первая итерация у нас безусловная, напечатали звездочку, результат целочисленного деления сохранили в i = 1. Выполняем проверку условия - результат целочисленного деления 1/2 (с отбрасыванием дробной части) - 0. Выходим из цикла. Вроде бы все просто, отвечаю «одну». В конце теста узнаю, что этот ответ мне не засчитали.

Компилирую этот код gcc (linux,x86_64), результат получаю тот же - одна звезда:

[popov@PopovIansWorkstation ~]$ cat test1.cpp 
#include <iostream>
int main(int argc, char **argv) {
  int i = 5;
  do {
    std::cout << '*';
    i /= 4;
  } while (i/2);
  std::cout << std::endl;
  return 0;
}
[popov@PopovIansWorkstation ~]$ g++ test1.cpp && ./a.out 
*
[popov@PopovIansWorkstation ~]$ 
Ошибка в тесте, подумал я и написал об этом в geekbrains. Специалист, с которым я связался, уточнил этот вопрос у ответственного лица, и ответил мне, что верный ответ «две звезды». Я не стал настаивать на своей правоте, вдруг в этом примитивном коде я упустил что-то важное. Потому хочу обсудить этот вопрос с вами.

 , ,

popov-aa
()

Реакция фронтенда на изменения данных на сервере при оповещении через websocket

Имеется бэкенд на springboot. Работа с БД осуществляется посредством spring-data-jpa. Еще есть фронтенд на vuejs.

Захотелось мне реализовать обновление страницы при изменении данных на сервере, для чего я завел websocket (sockjs, stomp). Вебсокет планирую пока использовать только для оповещения сервером всех заинтересованных об изменении данных.

Вопрос первый, об организации каналов оповещения. Допустим у меня есть четыре сущности: A, B, C, D. Еще есть три компонента:

  • cAB, его состояние зависит от сущностей A и B
  • cCD, его состояние зависит от сущностей C и D
  • cABC, его состояние зависит от сущностей A, B и C

Сущности могут изменяться на сервере в рамках одной транзакции в различных комбинациях. Хотелось бы минимизировать число обновлений компонентов при изменении данных на сервере.

Допустим вызов одного ресурса производит изменение сущностей A, B, C. В итоге я хотел бы чтобы в результате все три компонента обновились по одному разу.

Вариант первый: создать по каналу на сущность и при изменении каждой сущности постить в соответствующий ей канал сообщение. Каждый компонент подписывается на каналы сущностей, от которых зависит его состояние. Но тогда компонент cAB обновится два раза, первый раз по сообщению от канала A, второй раз по изменению по сообщению канала B. Решить эту проблему можно заведя таймер, который сбрасывался бы получив каждое сообщение. По таймауту происходило бы обновление. Таким образом следующие друг за другом сообщения приводили бы к одному единственному обновлению. Но тут надо во vuejs реализовывать эту логику на таймерах. И вообще нормальные ли это решение?

Вариант второй: сообщение об обновлении постилось бы в один единственный канал, сообщение содержало бы список сущностей, которые изменились. Минус один и существенный на мой взгляд: любой клиент получал бы сообщения об обновлении сущностей, которые ему даже не интересы в этот момент. А у меня есть сущности, которые обновляются раз в 5 секунд.

Какие есть более оптимальные варианты на ваш взгляд?

Вопрос второй. Так как клиенты не будут слать серверу никаких сообщений по вебсокету, аннотации @MessageMapping @SendTo для меня бесполезны, ибо отправка сообщений будет происходить из контроллеров rest посредством вызова SimpMessagingTemplate.this.template.convertAndSend Но транзакция закрывается при выходе из транзакционного метода. Получается даже если я вызываю convertAndSend в конце метода контроллера, данные еще не зафиксированы, а я уже шлю сообщение клиентам. Каким образом организовать отправку сообщения клиентам после успешной фиксации транзакции? Этот вопрос может быть связан со следующим.

Если подход с отправкой сообщения об изменении сущностей в канал соответствующий этой сущности является оптимальным, то я хотел автоматизировать отправку сообщений, чтобы в каждом методе контроллеров не приходилось вести учет сущностей, который я меняю. В голову пришла такая мысль: обрабатывать фиксацию транзакций, в каждом событии анализировать сущности, которые были повержены изменению, постить в каналы соответствующие этим сущностям сообщения. Это возможно технически? Отследить успешный коммит транзакции и перебрать измененные сущности в этой транзакции? И насколько кошерен этот подход?

Еще есть вариант, создавать на каждый компонент свой канал, и чтобы сервер при изменении сущностей постил сообщения в каналы компонентов, которые зависят от этих сущностей. Но для этого на сервере нужно поддерживать список компонентов с зависимостями от сущностей. Мне кажется это совсем фу.

Буду рад любым комментариям и советам.

 , , ,

popov-aa
()

Занять свободное пространство в bootstrap

Имеется кусок код вида:

<div class="container-fluid p-4">
    <h3 class="mb-4"><b-breadcrumb :items="pagePath"/></h3>
    <div class="row">
        <device-types-component class="h-auto mb-4 mr-4"/>
        <android-client-update-channels-component class="h-auto mb-4 w-auto"/>
    </div>
</div>

Выглядит это вот так.

Вопрос первый: как сделать так, чтобы один из блоков занимал всю оставшуюся ширину? Вопрос второй: как сделать так, чтобы оба блока занимали всю оставшуюся ширину? Вопрос третий: как сделать так, чтобы блоки занимали всю оставшуюся доступную высоту?

Извиняюсь заранее за нубские вопросы. Я в вебе не силен.

 , ,

popov-aa
()

Каскадное удаление связных сущностей

У меня есть несколько связных сущностей:

@NoArgsConstructor
@Getter @Setter
@Entity
public class Organization extends AbstractIdentifiable {

    @Column(nullable = false, unique = true)
    @NotBlank
    private String title;

    @ManyToOne(optional = false)
    @JoinColumn(nullable = false)
    private Member registrationMember;

    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar registrationDateTime;

    @OneToOne(mappedBy = "organization", cascade = CascadeType.ALL)
    private Site site;

    @OneToOne(mappedBy = "organization", cascade = CascadeType.ALL)
    private Advertiser advertiser;

}

@NoArgsConstructor
@Getter @Setter
@Entity
public class Advertiser extends AbstractIdentifiable {

    @OneToOne(optional = false)
    @JoinColumn(nullable = false)
    private Organization organization;

    @ManyToMany(mappedBy = "advertisers")
    private Set<Member> members = new HashSet<>();

    @OneToMany(mappedBy = "advertiser", cascade = CascadeType.ALL)
    private Set<PaidVideo> paidVideos = new HashSet<>();

}
@NoArgsConstructor
@Getter @Setter
@Entity
public class PaidVideo extends AbstractIdentifiable {

    @OneToOne(optional = false)
    @JoinColumn(nullable = false)
    private Video video;

    @ManyToOne(optional = false)
    @JoinColumn(nullable = false)
    private Advertiser advertiser;

    @OneToMany(mappedBy = "paidVideo", cascade = CascadeType.ALL)
    private Set<Booking> bookings = new HashSet<>();

}

Перечислил только те, что имеют непосредственное отношение к вопросу, от общей сущности (вверху), к зависимым (внизу).

Пытаюсь удалить сущность Organization. Ожидаю, что по каскадной операции (cascade = CascadeType.ALL) будут удалены все связные сущности: Advertiser, PaidVideo и так далее:

@Log4j2
@Controller
@RequestMapping("/api/organizations")
public class OrganizationController {

    @Autowired
    private OrganizationRepository organizationRepository;

    @PreAuthorize("hasRole('ADMIN')")
    @Transactional
    @RequestMapping(value = "/{id}/delete", method = RequestMethod.POST)
    public ResponseEntity delete(@PathVariable("id") Long id) {
        organizationRepository.deleteById(id);
        return ResponseEntity.ok().build();
    }

}

Однако этого не происходит. Hibernate выкачивает все связные сущности, а после пытается первой и единственной удалить сущность Advertiser, закономерно получая ошибку ограничения целостности: https://pastebin.com/Z0M9BdM7

Чем может быть вызвано такое поведение? Разве hibernate не должен был построить дерево зависимостей сущностей и удалять их начиная с листьев? Почему при удалении Organization происходит только попытка удаления Advertiser, игнорируя зависимые сущности Advertiser? При чем это единственная попытка удаления чего либо, она происходит при вызове метода organizationRepository.deleteById(id); и после происходит выход из транзакционного метода, и коммит транзакции. В общем, колдунство какое-то.

Граф связей таблиц в БД: https://i.imgur.com/lPixAnd.png

 , , , ,

popov-aa
()

Jackson2 && MixIn

Есть две связные сущности: Organization самодостаточна, Site имеет ссылку на нее:

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Site extends AbstractIdentifiable {

    @OneToOne(optional = false)
    private Organization organization;

    @ManyToMany(mappedBy = "sites", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<Member> members = new HashSet<>();

    @OneToMany(mappedBy = "site", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<Location> locations = new HashSet<>();

    public Site() {
    }

    public Organization getOrganization() {
        return organization;
    }

    public void setOrganization(Organization organization) {
        this.organization = organization;
    }

    public Set<Member> getMembers() {
        return members;
    }

    public void setMembers(Set<Member> members) {
        this.members = members;
    }

    public Set<Location> getLocations() {
        return locations;
    }

    public void setLocations(Set<Location> locations) {
        this.locations = locations;
    }

}
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

@Entity
public class Organization extends AbstractIdentifiable implements Serializable {

    @Column(nullable = false)
    @NotBlank
    private String title;

    @OneToOne(mappedBy = "organization", cascade = CascadeType.ALL)
    private Site site;

    @OneToOne(mappedBy = "organization", cascade = CascadeType.ALL)
    private Advertiser advertiser;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Site getSite() {
        return site;
    }

    public void setSite(Site site) {
        this.site = site;
    }

    public Advertiser getAdvertiser() {
        return advertiser;
    }

    public void setAdvertiser(Advertiser advertiser) {
        this.advertiser = advertiser;
    }

}

Когда я сериализую Site приложение зацикливается из-за циклических ссылок. Поставить @JsonIgnore в сущности Organization у поля site нельзя, ибо в другом месте программы потребуется сериализовать сущность Organization как корневую, с сериализацией Organization как вложенной сущности. На помощь приходит MixIn. Делаю так:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.helan.adkiosk.entitiy.Advertiser;
import com.helan.adkiosk.entitiy.Site;

public interface OrganizationMixIn {

    @JsonIgnore
    public Site getSite();

    @JsonIgnore
    public Advertiser getAdvertiser();

}
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.helan.adkiosk.entitiy.Location;
import com.helan.adkiosk.entitiy.Member;

import java.util.Set;

public interface SiteWithOrganizationMixIn {

    @JsonIgnore
    public Set<Member> getMembers();

    @JsonIgnore
    public Set<Location> getLocations();

}
public String index() throws JsonProcessingException {
    ObjectMapper mapperWithMixIn = new ObjectMapper();
    mapperWithMixIn.addMixIn(Site.class, SiteWithOrganizationMixIn.class);
    mapperWithMixIn.addMixIn(Organization.class, OrganizationMixIn.class);
    return mapperWithMixIn.writeValueAsString(siteRepository.findAll());
}

Все работает как и задумывалось. Не устраивает только то, что я должен явно указывать поля в каждом MixIn, которые я не хочу сериализовывать с помощью аннотации JsonIgnore. Есть ли возможность реализовать обратную логику: по умолчанию сериализация отключена для всех полей, и в каждом MixIn я должен включить определенные поля? Или еще лучше, Изначально в сущности я указываю поля, которые сериализуются, а затем добавляю еще требуемые в каждом MixIn?

Еще вопрос, в mvc могу ли я не создавать в явном виде ObjectMapper и вызывать сериализацию в строку, а указать с помощью какой-нибудь аннотации используемые в сериализации набор MixIn и возвращать ссылку объект из метода контроллера?

 , ,

popov-aa
()

Непривилегированные контейнеры LXC в Centos7

Возможно ли? Вот, что у меня получается:

[popov@PopovServer ~]$ cat /etc/subuid
popov:100000:65536

[popov@PopovServer ~]$ cat /etc/subgid
popov:100000:65536

[popov@PopovServer ~]$ cat ~/.config/lxc/default.conf
lxc.network.type = veth
lxc.network.link = virbr0
lxc.network.flags = up
lxc.kmsg = 0
lxc.start.auto = 1
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536

[popov@PopovServer ~]$ lxc-create -n test -t download -- -d centos -r 7 -a amd64
lxc: conf.c: lxc_map_ids: 3638 Missing newuidmap/newgidmap
error mapping child
setgid: Invalid argument
lxc_container: lxccontainer.c: do_create_container_dir: 767 Failed to chown container dir
lxc_container: lxc_create.c: main: 274 Error creating container test

[popov@PopovServer ~]$ cat /etc/sysctl.conf
net.ipv4.ip_forward = 1
kernel.unprivileged_userns_clone = 1

[popov@PopovServer ~]$ sudo sysctl -p /etc/sysctl.conf
[sudo] пароль для popov:
net.ipv4.ip_forward = 1
sysctl: cannot stat /proc/sys/kernel/unprivileged_userns_clone: Нет такого файла или каталога

[popov@PopovServer ~]$ uname -a
Linux PopovServer 4.18.5-1.el7.elrepo.x86_64 #1 SMP Fri Aug 24 11:35:05 EDT 2018 x86_64 x86_64 x86_64 GNU/Linux
В сети какая-то противоречивая информация. Якобы на стандартном (старом) ядре чего-то не хватает. Я обновил ядро из сторонних реп, но не помогло.

 ,

popov-aa
()

LXC на CentOS7: Ошибка при операциях с маркером проверки подлинности

Добрый день. На только что установленном centos7 пытаюсь освоить lxc-контейнеры по одной из нескольких статей. Спотыкаюсь уже на второй команде.

[root@PopovServer lxc]# lxc-create -n CentOS-Rust -t centos
Host CPE ID from /etc/os-release: cpe:/o:centos:centos:7
Checking cache download in /var/cache/lxc/centos/x86_64/7/rootfs ...
Cache found. Updating...
Загружены модули: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirror.corbina.net
 * extras: mirror.reconn.ru
 * updates: mirror.reconn.ru
No packages marked for update
Загружены модули: fastestmirror
Сброс источников:base extras updates
0 package файлов удалены
Update finished
Copy /var/cache/lxc/centos/x86_64/7/rootfs to /var/lib/lxc/CentOS-Rust/rootfs ...
Copying rootfs to /var/lib/lxc/CentOS-Rust/rootfs ...
sed: невозможно прочитать /var/lib/lxc/CentOS-Rust/rootfs/etc/init/tty.conf: Нет такого файла или каталога
Storing root password in '/var/lib/lxc/CentOS-Rust/tmp_root_pass'
chpasswd: не удалось открыть /etc/passwd
Срок действия пароля пользователя root заканчивается.
passwd: Libuser error at line: 413 - Error replacing `/etc/passwd': Отказано в доступе.
passwd: Ошибка
sed: невозможно прочитать /var/lib/lxc/CentOS-Rust/rootfs/etc/rc.sysinit: Нет такого файла или каталога
sed: невозможно прочитать /var/lib/lxc/CentOS-Rust/rootfs/etc/rc.d/rc.sysinit: Нет такого файла или каталога

Container rootfs and config have been created.
Edit the config file to check/enable networking setup.

The temporary root password is stored in:

        '/var/lib/lxc/CentOS-Rust/tmp_root_pass'


The root password is set up as expired and will require it to be changed
at first login, which you should do as soon as possible.  If you lose the
root password or wish to change it without starting the container, you
can change it from the host by running the following command (which will
also reset the expired flag):

        chroot /var/lib/lxc/CentOS-Rust/rootfs passwd

[root@PopovServer lxc]# chroot /var/lib/lxc/CentOS-Rust/rootfs passwd
Изменяется пароль пользователя root.
Новый пароль :
Повторите ввод нового пароля :
passwd: Ошибка при операциях с маркером проверки подлинности
[root@PopovServer lxc]#

Пробовал и chroot делать на корень системы с вызовом passwd, и /etc/shadow удалял с последующим его генерированием трехбуквенной командой, уже забыл какой. Результат тот же.

Немного смущает, что у меня вывод слегка отличается от того, что в статье. Возможно при создании контейнера уже что-то пошло не так.

Например, вот: https://letsclearitup.com.ua/lxc/ustanovka-i-nastroyka-lxc-v-centos-7.html В статье:

Storing root password in '/var/lib/lxc/Lxc0/tmp_root_pass'
Expiring password for user root.
passwd: Success
У меня же:
Storing root password in '/var/lib/lxc/CentOS-Rust/tmp_root_pass'
chpasswd: не удалось открыть /etc/passwd
Срок действия пароля пользователя root заканчивается.
passwd: Libuser error at line: 413 - Error replacing `/etc/passwd': Отказано в доступе.
passwd: Ошибка

В чем может быть проблема?

[root@PopovServer lxc]# lxc-checkconfig
Kernel configuration not found at /proc/config.gz; searching...
Kernel configuration found at /boot/config-3.10.0-862.9.1.el7.x86_64
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
newuidmap is not installed
newgidmap is not installed
Network namespace: enabled
Multiple /dev/pts instances: enabled

--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled

--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
Bridges: enabled
Advanced netfilter: enabled
CONFIG_NF_NAT_IPV4: enabled
CONFIG_NF_NAT_IPV6: enabled
CONFIG_IP_NF_TARGET_MASQUERADE: enabled
CONFIG_IP6_NF_TARGET_MASQUERADE: enabled
CONFIG_NETFILTER_XT_TARGET_CHECKSUM: enabled

--- Checkpoint/Restore ---
checkpoint restore: enabled
CONFIG_FHANDLE: enabled
CONFIG_EVENTFD: enabled
CONFIG_EPOLL: enabled
CONFIG_UNIX_DIAG: enabled
CONFIG_INET_DIAG: enabled
CONFIG_PACKET_DIAG: enabled
CONFIG_NETLINK_DIAG: enabled
File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

[root@PopovServer lxc]#

 ,

popov-aa
()

Программа для блокировки экрана по расписанию

Коллега работает в gnome, я в xfce4. Я установил себе плагин, который принудительно с заданным интервалом устраивает перерыв, блокируя на это время экран. Все был бы доволен, но частенько бывает так, что коллега хочет чтобы я ему показал код, или наоборот, а у нас рассинхронизация. Либо он отдыхает, либо я. Подскажите программу с аналогичным функционалом, только чтобы перерыв происходил по расписанию, чтобы несколько человек были в одной фазе.

То есть чтобы каждую 55-ю минуту часа экран блокировался на пять минут, с возможностью отложить на минуту.

 ,

popov-aa
()

Регистрация в Selector из другого потока

Я хочу написать класс, который работал бы с несколькими сокетами в одном потоке. Для этой цели как нельзя лучше подходят SocketChannel и Selector.

С серверной часть проблем нет:

        Selector selector = SelectorProvider.provider().openSelector();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(socketAddress);
        serverSocketChannel.register(selector, serverSocketChannel.validOps());

        try {
            while (selector.select() > -1) {
                Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();
                while (selectionKeyIterator.hasNext()) {
                    SelectionKey selectionKey = selectionKeyIterator.next();
                    selectionKeyIterator.remove();

                    if (selectionKey.isValid()) {
                        if (!handleSelectionKey(selectionKey)) {
                            logger.debug("Unhandled selection key: " + selectionKey.hashCode() + ", " + selectionKey.readyOps());
                        }
                    }
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }

Все по секретным документам с хабра =) Пришел новый клиент - обработали isAcceptable.

Проблема с клиентской частью. Допустим я хочу иметь возможность подключаться к нескольким сокетам и обрабатывать их в одном потоке.

Запускаю в одном потоке:

while (selector.select() > -1)
Теперь если из другого потока я вызову:
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(socketAddress);
        socketChannel.register(selector, socketChannel.validOps());
И на register мы зависнем, ибо select захватил монитор и не отпускает его. Полагаю, что регистрироваться мы должны в том же потоке, где и происходит обработка select. Наверное нужно перед запуском цикла опроса Select зарегистрировать в нем на прослушивание своей операции аля WantToConnect, при возникновении необходимости подключиться к новому сокету из другого потока каким-то образом будить Selector, сообщать ему что пришло данное событие. Каким образом это можно сделать?

 , ,

popov-aa
()

Создание дочернего ApplicationContext в другом потоке

Для изучения Java и сопутствующих технологий я поставил себе задачу: в свободное от работы время переписать рабочий проект с C++/Qt/OSGEarth на Java/NasaWorldWind.

Это позволит мне познакомиться и с Spring, и с Hibernate и Swing/JavaFX и с WorldWind.

Вот мой репозиторий проекта: https://github.com/popov-aa/GeoEditor Прошу не ругать стиль и отсутствие комментариев. Это чисто учебный проект.

Так как версии интерфейсов будет две, Swing и JavaFX, каждый со своим набором бинов, реализующих окна, я решил что в точке входа (класс com.popov.GeoEditor.GeoEditor) будет создаваться основной ApplicationContext, включающий в себя общие бины.

Далее ссылка на этот ApplicationContext в зависимости от аргументов запуска будет передаваться в объект отвечающий за запуск Swing (com.popov.GeoEditor.launcher.SwingLauncher) или JavaFX (com.popov.GeoEditor.launcher.JavaFXLauncher) версий, в которых будет создаваться свой дочерний ApplicationContext.

Когда я запускаю swing-версию никаких проблем нет:

mvn exec:java -Dexec.args="swing"
Создание всех ApplicationContext и бинов происходит в главном потоке приложения, а в конце просто отображается окно.

Когда запускается JavaFX-версия приложения, указатель на родительский ApplicationContext сохраняется как поле класса JavaFXLauncher и после этого запускается javafx.application.Application.

mvn exec:java -Dexec.args="javafx"

Если создавать дочерний ApplicationContext в потоке JavaFX, в методе start, указатель на родительский ApplicationContext уже будет равен null. Бины JavaFX не будут иметь доступа к общим бинам и ничего не запустится. Если создавать дочерний ApplicationContext в основном потоке, в методе, в который передается указатель на общий ApplicationContext, тогда приложение падает из-за попытке создания JavaFX-окон не в JavaFX-потоке, ибо бины не ленивые.

Собственно, вопрос: почему когда запускается JavaFX-поток обнуляется указатель на родительский ApplicationContext (JavaFXLauncher.generalApplicationContext)? Кто его обнуляет?

Я был уверен в том, что объект в Java будет существовать до тех пор, пока на него есть хоть одна ссылка. Ссылку generalApplicationContext я устанавливаю в методе launch(ApplicationContext applicationContext, String[] args) и больше нигде не модифицирую. И вдруг в другом потоке она оказывается равно null.

Есть какие-то правила, касательно того, что связанные друг с другом ApplicationContext должны быть созданы в одном и том же потоке? Я подобной информации не нашел.

И мне казалось, что в Java, в отличие от Qt, нет таких заморочек, ибо отсутствуют встроенные очереди событий.

 ,

popov-aa
()

RSS подписка на новые темы