release version 1.11.0
This commit is contained in:
175
platform/runtime/base/cellar-extensions/LICENSE.txt
Normal file
175
platform/runtime/base/cellar-extensions/LICENSE.txt
Normal file
@ -0,0 +1,175 @@
|
||||
ЛИЦЕНЗИЯ ОГРАНИЧЕННОГО ПРИМЕНЕНИЯ
|
||||
|
||||
Настоящий документ устанавливает для Пользователя условия применения Базовой (некоммерческой)
|
||||
версии лицензии для пробного использования программного обеспечения ENTAXY, принадлежащего
|
||||
Правообладателю – Обществу с ограниченной ответственностью "ЕМДЕВ" (ОГРН 1057810026658, ИНН
|
||||
7813313860, юридический адрес: 197022, Россия, г. Санкт-Петербург, ул. Профессора Попова,
|
||||
д. 23, литера В, помещение 3Н), расположенной в сети Интернет по адресу
|
||||
https://www.emdev.ru/about (далее - Компания).
|
||||
|
||||
Используя или получая доступ к Программному обеспечению, или нажав «Я согласен с Условиями»
|
||||
(или аналогичную кнопку или флажок) после загрузки или установки Программного обеспечения,
|
||||
Пользователь выражает свое согласие на обязательность условий и ограничений, изложенных в
|
||||
настоящем документе, в противном случае, он должен не использовать или не получать доступ
|
||||
к Программному обеспечению.
|
||||
|
||||
1. ТЕРМИНЫ И ОПРЕДЕЛЕНИЯ
|
||||
|
||||
a) ПО – Программное обеспечение, интеграционная шина «ЭНТАКСИ» (ENTAXY) в любой ее версии
|
||||
или редакции, исключительные права на которую принадлежат Правообладателю.
|
||||
b) Правообладатель (Компания) – ООО «ЕМДЕВ», ОГРН 1057810026658, ИНН 7813313860, исключительные
|
||||
права которого подтверждаются Свидетельством о государственной регистрации в Реестре программ
|
||||
для ЭВМ № 2021610848 от 19.01.2021 года.
|
||||
c) Пользователь – юридическое или физическое лицо, получившее через скачивание с сайта
|
||||
https://entaxy.ru или иным образом, дистрибутив ПО, пользующееся ПО.
|
||||
d) ИС – интеллектуальная собственность – закреплённое законом исключительное право, а также
|
||||
личные неимущественные права авторов произведений на результат интеллектуальной деятельности.
|
||||
e) Подписка – это коммерческое предложение Правообладателя, состоящее из Лицензии на использование
|
||||
ПО и доступа к технической поддержке программного обеспечения на срок Подписки. Подписка
|
||||
включает предоставление Пользователю неисключительного права использования ПО, в том числе
|
||||
получение обновлений функционала ПО и безопасности ПО, исправление ошибок ПО и получение
|
||||
патчей с обновлениями и исправлениями программного обеспечения. Подписка приобретается
|
||||
Пользователем на период времени, указанный в Сертификате. Количество подписок устанавливается
|
||||
для каждого Пользователя индивидуально в Сертификате.
|
||||
f) Сертификат – документ, выдаваемый Дистрибъютором или Авторизованным партнёром (Партнёром),
|
||||
подтверждающий факт приобретения физическим или юридическим лицом Подписки на программное
|
||||
обеспечение в ограниченном объёме и на определённый период времени.
|
||||
g) Лицензия (простая (неисключительная) – совокупность ограниченных прав использования ПО,
|
||||
предоставленных Пользователю согласно условиям Подписки.
|
||||
h) Библиотека – совокупность подпрограмм и объектов, используемых для разработки программного
|
||||
обеспечения.
|
||||
i) Исходный код – текст компьютерной программы на каком-либо языке программирования, состоящий
|
||||
из одного или нескольких файлов, который может быть прочтён человеком.
|
||||
j) Объектный код – файл (часть машинного кода) с промежуточным представлением отдельного модуля
|
||||
программы, полученный в результате обработки исходного кода, еще не связанный в полную программу.
|
||||
Это машинный код для одной конкретной библиотеки или модуля, который будет составлять готовый
|
||||
продукт.
|
||||
k) Некоммерческое использование – индивидуальное личное использование Пользователем программного
|
||||
обеспечения с целью обучения работе с Программным обеспечением, для оценки или демонстрации
|
||||
возможностей Программного обеспечения, при котором, Пользователем не извлекается коммерческая
|
||||
выгода и/или не идёт в доход денежное вознаграждение при использовании Программного обеспечения.
|
||||
|
||||
2. ДОПУСТИМЫЕ СПОСОБЫ ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
|
||||
|
||||
2.1. Правообладатель предоставляет Пользователю ограниченное право использования Программного
|
||||
обеспечения на условиях простой (неисключительной) лицензии в объёме, ограниченном правом
|
||||
воспроизведения полной рабочей версии программного обеспечения, новых версий программного обеспечения
|
||||
в памяти оборудования и его запуска на оборудовании в соответствии со ст. 1280 ГК РФ.
|
||||
2.2. Право на использование Программного обеспечения, предоставляемое Пользователю, носит
|
||||
неисключительный характер.
|
||||
2.3. Пользователю предоставляется всемирная, неисключительная, не подлежащая сублицензированию,
|
||||
лицензия на ограниченное использование Программного обеспечения.
|
||||
2.4. Пользователь, имеющий Базовую (некоммерческую) версию лицензии для пробного использования
|
||||
имеет право приобрести Подписку на программное обеспечение. В этом случае Пользователь обязан
|
||||
обратиться в службу поддержки Правообладателя по адресу: https://entaxy.ru/ для изменения
|
||||
вида лицензии с Базовой бесплатной версии на Подписки.
|
||||
2.5. Срок использования скачанной Пользователем базовой (некоммерческой) версии лицензии для
|
||||
пробного использования программного обеспечения – не ограничен.
|
||||
2.6. Использование Пользователем настоящего программного обеспечения в целях разработки,
|
||||
модификации, обновления другого ПО, принадлежащего третьим лицам, а не Правообладателю,
|
||||
без разрешения Правообладателя не допускается.
|
||||
|
||||
3. АВТОРСКОЕ ПРАВО.
|
||||
|
||||
3.1. Все авторские права, все права интеллектуальной собственности на Программное обеспечение
|
||||
и любые его копии принадлежат Правообладателю.
|
||||
3.2. Все авторские права, все права интеллектуальной собственности в отношении любого контента,
|
||||
к которому можно получить доступ с помощью Программного обеспечения, является собственностью
|
||||
соответствующего владельца контента и защищается применимым законодательством об авторском
|
||||
праве или другими законами и договорами об интеллектуальной собственности.
|
||||
3.3. Условия использования Программного обеспечения.
|
||||
Лицензия, предоставленная Пользователю, действительна только в том случае, если Пользователь
|
||||
придерживается следующих условий:
|
||||
3.3.1. Принятие уведомлений об авторских правах. Пользователю запрещается удалять или изменять
|
||||
какие-либо уведомления об авторских правах или лицензиях, которые появляются при использовании
|
||||
Программного обеспечения или на нем.
|
||||
3.3.2. Модификация. Пользователю запрещается модифицировать, изменять, декомпилировать,
|
||||
расшифровывать, дизассемблировать, переводить или реверсировать, перепроектировать
|
||||
Программное обеспечение.
|
||||
3.3.3. Распространение. Пользователю запрещается сублицензировать, передавать право использования
|
||||
ПО или иным образом распространять или предоставлять Программное обеспечение любой третьей стороне.
|
||||
3.3.4. SaaS. За исключением случаев, когда это разрешено Правообладателем, Пользователю запрещено
|
||||
использовать Программное обеспечение в коммерческих целях для оказания услуг третьим лицам.
|
||||
|
||||
4. ОТВЕТСТВЕННОСТЬ ПРАВООБЛАДАТЕЛЯ ПРИ НАРУШЕНИИ ПОЛЬЗОВАТЕЛЕМ ПРАВ «ИС»
|
||||
|
||||
4.1. Правообладатель не несет никаких обязательств в отношении каких-либо претензий к Пользователю
|
||||
на предмет нарушения последним прав Интеллектуальной собственности, возникших в связи с
|
||||
использованием Пользователем:
|
||||
4.1.1. Любых компонентов программного обеспечения с открытым исходным кодом, включенных в
|
||||
Программное обеспечение;
|
||||
4.1.2. Любого нарушения правил использования Программного обеспечения, установленного условиями
|
||||
настоящего соглашения;
|
||||
4.1.3. Любого использования Программного обеспечения в сочетании с другими ПО, оборудованием,
|
||||
или данными, не предоставленными Пользователю Правообладателем;
|
||||
4.1.4. Любого изменения Программного обеспечения любым третьим лицом, а не Правообладателем.
|
||||
|
||||
|
||||
5. НАСТОЯЩИМ ПРАВООБЛАДАТЕЛЬ ЗАЯВЛЯЕТ, ЧТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ ПОЛЬЗОВАТЕЛЮ
|
||||
ПО ПРИНЦИПУ «AS IS» - «КАК ЕСТЬ». НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ ПРАВООБЛАДАТЕЛЬ НЕ ГАРАНТИРУЕТ
|
||||
И НЕ ОБЕЩАЕТ, ЧТО ПРЕДОСТАВЛЕННОЕ ИМ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ БУДЕТ ПОДХОДИТЬ ИЛИ НЕ ПОДХОДИТЬ
|
||||
ДЛЯ КОНКРЕТНЫХ ЦЕЛЕЙ ПОЛЬЗОВАТЕЛЯ, ЧТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ БУДЕТ ОТВЕЧАТЬ ВСЕМ КОММЕРЧЕСКИМ
|
||||
И ЛИЧНЫМ СУБЪЕКТИВНЫМ ОЖИДАНИЯМ ПОЛЬЗОВАТЕЛЯ, ЧТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ БУДЕТ РАБОТАТЬ
|
||||
ИСПРАВНО, БЕЗ ТЕХНИЧЕСКИХ ОШИБОК, БЫСТРО И БЕСПЕРЕБОЙНО.
|
||||
|
||||
6. ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ.
|
||||
НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ ПРАВООБЛАДАТЕЛЬ ИЛИ ЕГО АФФИЛЛИРОВАННЫЕ ЛИЦА НЕ НЕСУТ ПЕРЕД ПОЛЬЗОВАТЕЛЕМ
|
||||
ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЯМЫЕ ИЛИ КОСВЕННЫЕ УБЫТКИ ПОЛЬЗОВАТЕЛЯ, ЕГО РАСХОДЫ ИЛИ РЕАЛЬНЫЙ УЩЕРБ,
|
||||
ВКЛЮЧАЯ, ПОМИМО ПРОЧЕГО, ПРОСТОИ; УТРАТУ БИЗНЕСА; УПУЩЕННУЮ ВЫГОДУ; НЕДОПОЛУЧЕННУЮ ПРИБЫЛЬ;
|
||||
ПОТЕРЮ ИЛИ ПОВРЕЖДЕНИЕ ДАННЫХ, ИМУЩЕСТВА И ИНОЕ.
|
||||
ОГРАНИЧЕНИЯ ПРИМЕНЯЮТСЯ НЕЗАВИСИМО ОТ ОСНОВАНИЯ НАСТУПЛЕНИЯ ОТВЕТСТВЕННОСТИ; В ТОМ ЧИСЛЕ ВСЛЕДСТВИЕ
|
||||
ДЕЙСТВИЯ ИЛИ БЕЗДЕЙСТВИЯ, НЕБРЕЖНОСТИ, УМЫСЛА, ПРЯМОГО ИЛИ КОСВЕННОГО; НЕОСТОРОЖНОСТИ; ЗАБЛУЖДЕНИЯ;
|
||||
КЛЕВЕТЫ; НАРУШЕНИЯ КОНФИДЕНЦИАЛЬНОСТИ ИЛИ ПРАВА ИНТЕЛЛЕКТУАЛЬНОЙ СОБСТВЕННОСТИ; ИЛИ ЛЮБОЕ ДРУГОЕ
|
||||
ОСНОВАНИЕ НАСТУПЛЕНИЯ ОТВЕТСТВЕННОСТИ.
|
||||
|
||||
7. ОБЯЗАННОСТЬ ПОЛЬЗОВАТЕЛЯ:
|
||||
Не осуществлять самостоятельно и (или) с привлечением третьих лиц нижеследующие действия
|
||||
(включая, но не ограничиваясь) по:
|
||||
-дизассемблированию и (или) декомпилированию (преобразованию объектного кода в исходный код)
|
||||
Программного обеспечения;
|
||||
-модификации Программного обеспечения, в том числе вносить изменения в объектный код, исходный
|
||||
код Программного обеспечения, за исключением тех изменений, которые вносятся средствами,
|
||||
включёнными в Программное обеспечение и описанными непосредственно в документации к нему;
|
||||
-созданию условий для использования Программного обеспечения лицами, не имеющими прав на
|
||||
использование данного Программного обеспечения, включая (но не ограничиваясь) вмешательство
|
||||
третьих лиц в функционирование Программного обеспечения, предоставление третьим лицам доступа
|
||||
к исследованию и (или) замене настроек Программного обеспечения, включая его первичную установку;
|
||||
-распространению Программного обеспечения в целом или в части (включая приложенную к нему документацию).
|
||||
|
||||
8. БИБЛИОТЕКА ПО. ИСПОЛЬЗУЕМЫЕ ПРОГРАММНЫЕ СРЕДСТВА.
|
||||
|
||||
8.1. Настоящим, Правообладатель заверяет, что Библиотека программного обеспечения состоит из
|
||||
лицензионных продуктов, используемых на законных основаниях, а
|
||||
именно https://entaxy.ru/libs/licenses/root-aggregated.deps.
|
||||
8.2. Любые программные средства, применяемые Пользователем при работе с ПО, должны быть
|
||||
совместимы с библиотекой ПО, указанной в п.8.1. настоящего соглашения.
|
||||
8.3. Перечень внешних модулей ПО, указанный в п.8.1 настоящего соглашения, может изменяться
|
||||
Правообладателем в одностороннем порядке, в зависимости от выпуска релизов программного обеспечения,
|
||||
содержащих все изменения и дополнения программного обеспечения.
|
||||
|
||||
9. ВНЕСЕНИЕ ИЗМЕНЕНИЙ В ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ.
|
||||
|
||||
9.1. Программное обеспечение, интеграционная шина «ЭНТАКСИ» (ENTAXY) является свободно распространяемым
|
||||
программным обеспечением.
|
||||
9.2. Пользователь имеет право вносить изменения в исходный код программного обеспечения исключительно
|
||||
с согласия Правообладателя в порядке предложения изменений/правок/дополнений через механизм
|
||||
«Pull Requests» в открытом репозитории Правообладателя по адресу: https://git.entaxy.ru/entaxy/entaxy-public.
|
||||
9.3. Любые изменения программного обеспечения, осуществляемые Пользователем без соблюдения условий
|
||||
пункта 9.2. настоящего документа, являются нарушением авторских и смежных прав Правообладателя,
|
||||
прав интеллектуальной собственности Правообладателя и влекут применение к Пользователю мер
|
||||
ответственности в соответствии с условиями настоящей Лицензии, а также применимого законодательства
|
||||
Российской Федерации.
|
||||
|
||||
10. ЗАКЛЮЧИТЕЛЬНЫЕ ПОЛОЖЕНИЯ.
|
||||
|
||||
10.1. В случае нарушения Пользователем любого из условий настоящей Лицензии, Правообладатель имеет
|
||||
право взыскать с Пользователя любые причинённые таким нарушением убытки, реальный ущерб,
|
||||
недополученную прибыль, упущенную выгоду, а также в случае нарушения Пользователем условий
|
||||
пункта 9.2 настоящего соглашения, в том числе, взыскать с Пользователя штраф в размере
|
||||
2 000 000 (Два миллиона) рублей за каждый установленный случай несанкционированного изменения
|
||||
исходного или объектного кода Программного обеспечения «Энтакси» (Entaxy).
|
||||
10.2. В рамках исполнения Пользователем обязательств по настоящей Лицензии, применимое
|
||||
законодательство – Российской Федерации.
|
||||
10.3. Если какое-либо положение настоящей Лицензии будет признано судом недействительным,
|
||||
остальные положения будут продолжать своё действие, а Пользователь будет обязан продолжать
|
||||
исполнять свои обязанности в соответствии с этими положениями.
|
89
platform/runtime/base/cellar-extensions/pom.xml
Normal file
89
platform/runtime/base/cellar-extensions/pom.xml
Normal file
@ -0,0 +1,89 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>ru.entaxy.esb.platform.runtime</groupId>
|
||||
<artifactId>base</artifactId>
|
||||
<version>1.11.0</version>
|
||||
</parent>
|
||||
<groupId>ru.entaxy.esb.platform.runtime.base</groupId>
|
||||
<artifactId>cellar-extensions</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
<name>ENTAXY :: PLATFORM :: BASE :: CELLAR EXTENSIONS</name>
|
||||
<description>ENTAXY :: PLATFORM :: BASE :: CELLAR EXTENSIONS</description>
|
||||
|
||||
<properties>
|
||||
<bundle.osgi.export.pkg>
|
||||
ru.entaxy.platform.runtime.cellar.helper,
|
||||
ru.entaxy.platform.runtime.cellar.sequence
|
||||
</bundle.osgi.export.pkg>
|
||||
<bundle.osgi.private.pkg>
|
||||
org.apache.karaf.features.internal.model,
|
||||
org.apache.felix.utils.version,
|
||||
org.apache.felix.utils.properties,
|
||||
org.apache.karaf.util,
|
||||
ru.entaxy.platform.runtime.cellar.sequence.process,
|
||||
ru.entaxy.platform.runtime.cellar.sequence.impl
|
||||
</bundle.osgi.private.pkg>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.configadmin</artifactId>
|
||||
<version>${felix.configadmin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.compendium</artifactId>
|
||||
<version>${osgi.compendium.version}</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.features</groupId>
|
||||
<artifactId>org.apache.karaf.features.core</artifactId>
|
||||
<version>${karaf.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ru.entaxy.esb.platform.runtime.base</groupId>
|
||||
<artifactId>base-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.karaf.shell</groupId>
|
||||
<artifactId>org.apache.karaf.shell.core</artifactId>
|
||||
</exclusion>
|
||||
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf</groupId>
|
||||
<artifactId>org.apache.karaf.util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.cellar</groupId>
|
||||
<artifactId>org.apache.karaf.cellar.core</artifactId>
|
||||
<version>${cellar.version}</version>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.cellar</groupId>
|
||||
<artifactId>org.apache.karaf.cellar.event</artifactId>
|
||||
<version>${cellar.version}</version>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.cellar</groupId>
|
||||
<artifactId>org.apache.karaf.cellar.features</artifactId>
|
||||
<version>${cellar.version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,738 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.helper;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.OpenType;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
import javax.management.openmbean.TabularData;
|
||||
import javax.management.openmbean.TabularDataSupport;
|
||||
import javax.management.openmbean.TabularType;
|
||||
|
||||
// import org.apache.karaf.cellar.bundle.BundleState;
|
||||
import org.apache.karaf.cellar.core.CellarSupport;
|
||||
import org.apache.karaf.cellar.core.ClusterManager;
|
||||
import org.apache.karaf.cellar.core.Configurations;
|
||||
import org.apache.karaf.cellar.core.Group;
|
||||
import org.apache.karaf.cellar.core.GroupManager;
|
||||
import org.apache.karaf.cellar.core.control.SwitchStatus;
|
||||
import org.apache.karaf.cellar.core.event.EventProducer;
|
||||
import org.apache.karaf.cellar.core.event.EventType;
|
||||
import org.apache.karaf.cellar.features.ClusterFeaturesEvent;
|
||||
import org.apache.karaf.cellar.features.ClusterRepositoryEvent;
|
||||
import org.apache.karaf.cellar.features.Constants;
|
||||
import org.apache.karaf.cellar.features.FeatureState;
|
||||
import org.apache.karaf.cellar.features.management.CellarFeaturesMBean;
|
||||
import org.apache.karaf.features.Feature;
|
||||
import org.apache.karaf.features.FeatureEvent;
|
||||
import org.apache.karaf.features.FeaturesService;
|
||||
import org.apache.karaf.features.RepositoryEvent;
|
||||
// import org.osgi.framework.BundleEvent;
|
||||
import org.apache.karaf.features.internal.model.Features;
|
||||
import org.apache.karaf.features.internal.model.JaxbUtil;
|
||||
import org.osgi.service.cm.ConfigurationAdmin;
|
||||
|
||||
/**
|
||||
* Implementation of the Cellar Features MBean.
|
||||
*/
|
||||
public class CellarFeaturesHelper implements CellarFeaturesMBean {
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
private GroupManager groupManager;
|
||||
private EventProducer eventProducer;
|
||||
private FeaturesService featuresService;
|
||||
private ConfigurationAdmin configurationAdmin;
|
||||
|
||||
public CellarFeaturesHelper() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ClusterManager getClusterManager() {
|
||||
return this.clusterManager;
|
||||
}
|
||||
|
||||
public void setClusterManager(ClusterManager clusterManager) {
|
||||
this.clusterManager = clusterManager;
|
||||
}
|
||||
|
||||
public GroupManager getGroupManager() {
|
||||
return this.groupManager;
|
||||
}
|
||||
|
||||
public void setGroupManager(GroupManager groupManager) {
|
||||
this.groupManager = groupManager;
|
||||
}
|
||||
|
||||
public EventProducer getEventProducer() {
|
||||
return eventProducer;
|
||||
}
|
||||
|
||||
public void setEventProducer(EventProducer eventProducer) {
|
||||
this.eventProducer = eventProducer;
|
||||
}
|
||||
|
||||
public FeaturesService getFeaturesService() {
|
||||
return featuresService;
|
||||
}
|
||||
|
||||
public void setFeaturesService(FeaturesService featuresService) {
|
||||
this.featuresService = featuresService;
|
||||
}
|
||||
|
||||
public ConfigurationAdmin getConfigurationAdmin() {
|
||||
return configurationAdmin;
|
||||
}
|
||||
|
||||
public void setConfigurationAdmin(ConfigurationAdmin configurationAdmin) {
|
||||
this.configurationAdmin = configurationAdmin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installFeature(String groupName, String name, String version, boolean noRefresh, boolean noStart,
|
||||
boolean noManage, boolean upgrade) throws Exception {
|
||||
// check if the group exists
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
// check if the producer is ON
|
||||
if (eventProducer.getSwitch().getStatus().equals(SwitchStatus.OFF)) {
|
||||
throw new IllegalStateException("Cluster event producer is OFF");
|
||||
}
|
||||
|
||||
// check if the feature is allowed outbound
|
||||
CellarSupport support = new CellarSupport();
|
||||
support.setClusterManager(this.clusterManager);
|
||||
support.setGroupManager(this.groupManager);
|
||||
support.setConfigurationAdmin(this.configurationAdmin);
|
||||
if (!support.isAllowed(group, Constants.CATEGORY, name, EventType.OUTBOUND)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Feature " + name + " is blocked outbound for cluster group " + groupName);
|
||||
}
|
||||
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
try {
|
||||
|
||||
// get the features in the cluster group
|
||||
Map<String, FeatureState> clusterFeatures =
|
||||
clusterManager.getMap(Constants.FEATURES_MAP + Configurations.SEPARATOR + groupName);
|
||||
|
||||
// check if the feature exist
|
||||
FeatureState feature = null;
|
||||
String key = null;
|
||||
|
||||
String targetKey = null;
|
||||
|
||||
// collect features to remove if upgrade = true
|
||||
List<String> featuresToRemove = new ArrayList<>();
|
||||
|
||||
for (String k : clusterFeatures.keySet()) {
|
||||
FeatureState state = clusterFeatures.get(k);
|
||||
key = k;
|
||||
if (version == null) {
|
||||
if (state.getName().equals(name)) {
|
||||
feature = state;
|
||||
targetKey = key;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (state.getName().equals(name)) {
|
||||
if (state.getVersion().equals(version)) {
|
||||
feature = state;
|
||||
targetKey = key;
|
||||
if (!upgrade)
|
||||
break;
|
||||
} else if (upgrade)
|
||||
featuresToRemove.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (feature == null) {
|
||||
if (version == null)
|
||||
throw new IllegalArgumentException(
|
||||
"Feature " + name + " doesn't exist in cluster group " + groupName);
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Feature " + name + "/" + version + " doesn't exist in cluster group " + groupName);
|
||||
}
|
||||
|
||||
// update the cluster group
|
||||
|
||||
// set previous features uninstalled if we upgrade
|
||||
// actual uninstallation will be executed on end nodes
|
||||
if (upgrade) {
|
||||
for (String featureKey : featuresToRemove) {
|
||||
FeatureState fs = clusterFeatures.get(featureKey);
|
||||
fs.setInstalled(false);
|
||||
clusterFeatures.put(featureKey, fs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// set current feature installed
|
||||
feature.setInstalled(true);
|
||||
clusterFeatures.put(targetKey, feature);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
|
||||
// broadcast the cluster event
|
||||
ClusterFeaturesEvent event = new ClusterFeaturesEvent(name, version, noRefresh, noStart, noManage, upgrade,
|
||||
FeatureEvent.EventType.FeatureInstalled);
|
||||
event.setSourceGroup(group);
|
||||
eventProducer.produce(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installFeature(String groupName, String name, String version) throws Exception {
|
||||
this.installFeature(groupName, name, version, false, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installFeature(String groupName, String name) throws Exception {
|
||||
this.installFeature(groupName, name, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void installFeature(String groupName, String name, boolean noRefresh, boolean noStart, boolean noManage,
|
||||
boolean upgrade) throws Exception {
|
||||
this.installFeature(groupName, name, null, noRefresh, noStart, noManage, upgrade);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallFeature(String groupName, String name, String version) throws Exception {
|
||||
this.uninstallFeature(groupName, name, version, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallFeature(String groupName, String name, String version, boolean noRefresh) throws Exception {
|
||||
// check if the group exists
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
// check if the producer is ON
|
||||
if (eventProducer.getSwitch().getStatus().equals(SwitchStatus.OFF)) {
|
||||
throw new IllegalStateException("Cluster event producer is OFF");
|
||||
}
|
||||
|
||||
// check if the feature is allowed outbound
|
||||
CellarSupport support = new CellarSupport();
|
||||
support.setClusterManager(this.clusterManager);
|
||||
support.setGroupManager(this.groupManager);
|
||||
support.setConfigurationAdmin(this.configurationAdmin);
|
||||
if (!support.isAllowed(group, Constants.CATEGORY, name, EventType.OUTBOUND)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Feature " + name + " is blocked outbound for cluster group " + groupName);
|
||||
}
|
||||
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
try {
|
||||
|
||||
// get the features in the cluster group
|
||||
Map<String, FeatureState> clusterFeatures =
|
||||
clusterManager.getMap(Constants.FEATURES_MAP + Configurations.SEPARATOR + groupName);
|
||||
|
||||
// check if the feature exist
|
||||
FeatureState feature = null;
|
||||
String key = null;
|
||||
for (String k : clusterFeatures.keySet()) {
|
||||
FeatureState state = clusterFeatures.get(k);
|
||||
key = k;
|
||||
if (version == null) {
|
||||
if (state.getName().equals(name)) {
|
||||
feature = state;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (state.getName().equals(name) && state.getVersion().equals(version)) {
|
||||
feature = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (feature == null) {
|
||||
if (version == null)
|
||||
throw new IllegalArgumentException(
|
||||
"Feature " + name + " doesn't exist in cluster group " + groupName);
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Feature " + name + "/" + version + " doesn't exist in cluster group " + groupName);
|
||||
}
|
||||
|
||||
// update the cluster group
|
||||
feature.setInstalled(false);
|
||||
clusterFeatures.put(key, feature);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
|
||||
// broadcast the cluster event
|
||||
ClusterFeaturesEvent event = new ClusterFeaturesEvent(name, version, noRefresh, false, false, false,
|
||||
FeatureEvent.EventType.FeatureUninstalled);
|
||||
event.setSourceGroup(group);
|
||||
eventProducer.produce(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallFeature(String groupName, String name) throws Exception {
|
||||
this.uninstallFeature(groupName, name, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallFeature(String groupName, String name, boolean noRefresh) throws Exception {
|
||||
this.uninstallFeature(groupName, name, null, noRefresh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabularData getFeatures(String groupName) throws Exception {
|
||||
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
CellarSupport support = new CellarSupport();
|
||||
support.setClusterManager(clusterManager);
|
||||
support.setGroupManager(groupManager);
|
||||
support.setConfigurationAdmin(configurationAdmin);
|
||||
|
||||
CompositeType featuresType = new CompositeType("Feature", "Karaf Cellar feature",
|
||||
new String[] {"name", "version", "installed", "located", "blocked"},
|
||||
new String[] {"Name of the feature", "Version of the feature",
|
||||
"Whether the feature is installed or not",
|
||||
"Location of the feature (on the cluster or the local node)",
|
||||
"Feature block policy"},
|
||||
new OpenType[] {SimpleType.STRING, SimpleType.STRING, SimpleType.BOOLEAN, SimpleType.STRING,
|
||||
SimpleType.STRING});
|
||||
|
||||
TabularType tabularType = new TabularType("Features", "Table of all Karaf Cellar features",
|
||||
featuresType, new String[] {"name", "version"});
|
||||
TabularData table = new TabularDataSupport(tabularType);
|
||||
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
try {
|
||||
Map<String, ExtendedFeatureState> features = gatherFeatures(groupName);
|
||||
if (features != null && !features.isEmpty()) {
|
||||
for (ExtendedFeatureState feature : features.values()) {
|
||||
|
||||
String located = "";
|
||||
boolean cluster = feature.isCluster();
|
||||
boolean local = feature.isLocal();
|
||||
if (cluster && local)
|
||||
located = "cluster/local";
|
||||
if (cluster && !local)
|
||||
located = "cluster";
|
||||
if (local && !cluster)
|
||||
located = "local";
|
||||
|
||||
String blocked = "";
|
||||
boolean inbound =
|
||||
support.isAllowed(group, Constants.CATEGORY, feature.getName(), EventType.INBOUND);
|
||||
boolean outbound =
|
||||
support.isAllowed(group, Constants.CATEGORY, feature.getName(), EventType.OUTBOUND);
|
||||
if (!inbound && !outbound)
|
||||
blocked = "in/out";
|
||||
if (!inbound && outbound)
|
||||
blocked = "in";
|
||||
if (!outbound && inbound)
|
||||
blocked = "out";
|
||||
|
||||
CompositeData data = new CompositeDataSupport(featuresType,
|
||||
new String[] {"name", "version", "installed", "located", "blocked"},
|
||||
new Object[] {feature.getName(), feature.getVersion(), feature.getInstalled(), located,
|
||||
blocked});
|
||||
table.put(data);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private Map<String, ExtendedFeatureState> gatherFeatures(String groupName) throws Exception {
|
||||
Map<String, ExtendedFeatureState> features = new HashMap<String, ExtendedFeatureState>();
|
||||
|
||||
// get cluster features
|
||||
Map<String, FeatureState> clusterFeatures =
|
||||
clusterManager.getMap(Constants.FEATURES_MAP + Configurations.SEPARATOR + groupName);
|
||||
for (String key : clusterFeatures.keySet()) {
|
||||
FeatureState state = clusterFeatures.get(key);
|
||||
ExtendedFeatureState extendedState = new ExtendedFeatureState();
|
||||
extendedState.setName(state.getName());
|
||||
extendedState.setInstalled(state.getInstalled());
|
||||
extendedState.setVersion(state.getVersion());
|
||||
extendedState.setCluster(true);
|
||||
extendedState.setLocal(true);
|
||||
features.put(key, extendedState);
|
||||
}
|
||||
|
||||
// get local features
|
||||
for (Feature feature : featuresService.listFeatures()) {
|
||||
String key = feature.getName() + "/" + feature.getVersion();
|
||||
if (features.containsKey(key)) {
|
||||
ExtendedFeatureState extendedState = features.get(key);
|
||||
if (featuresService.isInstalled(feature))
|
||||
extendedState.setInstalled(true);
|
||||
extendedState.setLocal(true);
|
||||
} else {
|
||||
ExtendedFeatureState extendedState = new ExtendedFeatureState();
|
||||
extendedState.setCluster(false);
|
||||
extendedState.setLocal(true);
|
||||
extendedState.setName(feature.getName());
|
||||
extendedState.setVersion(feature.getVersion());
|
||||
if (featuresService.isInstalled(feature))
|
||||
extendedState.setInstalled(true);
|
||||
else
|
||||
extendedState.setInstalled(false);
|
||||
features.put(key, extendedState);
|
||||
}
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRepositories(String groupName) throws Exception {
|
||||
// check if the group exists
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
// get the features repositories in the cluster group
|
||||
Map<String, String> clusterRepositories =
|
||||
clusterManager.getMap(Constants.REPOSITORIES_MAP + Configurations.SEPARATOR + groupName);
|
||||
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (String clusterRepository : clusterRepositories.keySet()) {
|
||||
result.add(clusterRepository);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRepository(String groupName, String nameOrUrl) throws Exception {
|
||||
this.addRepository(groupName, nameOrUrl, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRepository(String groupName, String nameOrUrl, String version) throws Exception {
|
||||
this.addRepository(groupName, nameOrUrl, version, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRepository(String groupName, String nameOrUrl, String version, boolean install) throws Exception {
|
||||
// check if the group exists
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
// check if the event producer is ON
|
||||
if (eventProducer.getSwitch().getStatus().equals(SwitchStatus.OFF)) {
|
||||
throw new IllegalStateException("Cluster event producer is OFF");
|
||||
}
|
||||
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
try {
|
||||
// get the features repositories in the cluster group
|
||||
Map<String, String> clusterRepositories =
|
||||
clusterManager.getMap(Constants.REPOSITORIES_MAP + Configurations.SEPARATOR + groupName);
|
||||
// get the features in the cluster group
|
||||
Map<String, FeatureState> clusterFeatures =
|
||||
clusterManager.getMap(Constants.FEATURES_MAP + Configurations.SEPARATOR + groupName);
|
||||
|
||||
URI uri = featuresService.getRepositoryUriFor(nameOrUrl, version);
|
||||
if (uri == null) {
|
||||
uri = new URI(nameOrUrl);
|
||||
}
|
||||
|
||||
// check if the URL is already registered
|
||||
String name = null;
|
||||
for (String repository : clusterRepositories.keySet()) {
|
||||
if (repository.equals(uri)) {
|
||||
name = clusterRepositories.get(repository);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (name == null) {
|
||||
// parsing the features repository to get content
|
||||
Features repository = JaxbUtil.unmarshal(uri.toASCIIString(), true);
|
||||
|
||||
// update the cluster group
|
||||
clusterRepositories.put(uri.toString(), repository.getName());
|
||||
|
||||
// update the features in the cluster group
|
||||
for (Feature feature : repository.getFeature()) {
|
||||
FeatureState state = new FeatureState();
|
||||
state.setName(feature.getName());
|
||||
state.setVersion(feature.getVersion());
|
||||
state.setInstalled(featuresService.isInstalled(feature));
|
||||
clusterFeatures.put(feature.getName() + "/" + feature.getVersion(), state);
|
||||
}
|
||||
|
||||
// broadcast the cluster event
|
||||
ClusterRepositoryEvent event =
|
||||
new ClusterRepositoryEvent(uri.toString(), RepositoryEvent.EventType.RepositoryAdded);
|
||||
event.setInstall(install);
|
||||
event.setSourceGroup(group);
|
||||
event.setSourceNode(clusterManager.getNode());
|
||||
eventProducer.produce(event);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Features repository URL " + uri + " already registered");
|
||||
}
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshRepository(String groupName, String nameOrUrl) throws Exception {
|
||||
// check if the group exists
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
// check if the event producer is ON
|
||||
if (eventProducer.getSwitch().getStatus().equals(SwitchStatus.OFF)) {
|
||||
throw new IllegalStateException("Cluster event producer is OFF");
|
||||
}
|
||||
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
try {
|
||||
String uri = null;
|
||||
if (nameOrUrl != null) {
|
||||
// get the cluster features repositories
|
||||
Map<String, String> clusterFeaturesRepositories =
|
||||
clusterManager.getMap(Constants.REPOSITORIES_MAP + Configurations.SEPARATOR + groupName);
|
||||
|
||||
for (Map.Entry<String, String> entry : clusterFeaturesRepositories.entrySet()) {
|
||||
if (entry.getKey().equals(nameOrUrl) || entry.getValue().equals(nameOrUrl)) {
|
||||
uri = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uri == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Features repository " + nameOrUrl + " doesn't exist in cluster group " + groupName);
|
||||
}
|
||||
}
|
||||
|
||||
// broadcast the cluster event
|
||||
ClusterRepositoryEvent event = new ClusterRepositoryEvent(uri, RepositoryEvent.EventType.RepositoryAdded);
|
||||
event.setRefresh(true);
|
||||
event.setSourceGroup(group);
|
||||
event.setSourceNode(clusterManager.getNode());
|
||||
eventProducer.produce(event);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRepository(String groupName, String repository) throws Exception {
|
||||
this.removeRepository(groupName, repository, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRepository(String groupName, String repo, boolean uninstall) throws Exception {
|
||||
// check if the group exists
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
// check if the event producer is ON
|
||||
if (eventProducer.getSwitch().getStatus().equals(SwitchStatus.OFF)) {
|
||||
throw new IllegalStateException("Cluster event producer is OFF");
|
||||
}
|
||||
|
||||
// get the features repositories in the cluster group
|
||||
Map<String, String> clusterRepositories =
|
||||
clusterManager.getMap(Constants.REPOSITORIES_MAP + Configurations.SEPARATOR + groupName);
|
||||
// get the features in the cluster group
|
||||
Map<FeatureState, Boolean> clusterFeatures =
|
||||
clusterManager.getMap(Constants.FEATURES_MAP + Configurations.SEPARATOR + groupName);
|
||||
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
|
||||
List<String> urls = new ArrayList<String>();
|
||||
Pattern pattern = Pattern.compile(repo);
|
||||
for (String repositoryUrl : clusterRepositories.keySet()) {
|
||||
String repositoryName = clusterRepositories.get(repositoryUrl);
|
||||
if (repositoryName != null && !repositoryName.isEmpty()) {
|
||||
// repository has name, try regex on the name
|
||||
Matcher nameMatcher = pattern.matcher(repositoryName);
|
||||
if (nameMatcher.matches()) {
|
||||
urls.add(repositoryUrl);
|
||||
} else {
|
||||
// the name regex doesn't match, fallback to repository URI regex
|
||||
Matcher uriMatcher = pattern.matcher(repositoryUrl);
|
||||
if (uriMatcher.matches()) {
|
||||
urls.add(repositoryUrl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// the repository name is not defined, use repository URI regex
|
||||
Matcher uriMatcher = pattern.matcher(repositoryUrl);
|
||||
if (uriMatcher.matches()) {
|
||||
urls.add(repositoryUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String url : urls) {
|
||||
// looking for the URL in the list
|
||||
boolean found = false;
|
||||
for (String repository : clusterRepositories.keySet()) {
|
||||
if (repository.equals(url)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
Features repositoryModel = JaxbUtil.unmarshal(url, true);
|
||||
|
||||
// update the features repositories in the cluster group
|
||||
clusterRepositories.remove(url);
|
||||
|
||||
// update the features in the cluster group
|
||||
for (Feature feature : repositoryModel.getFeature()) {
|
||||
clusterFeatures.remove(feature.getName() + "/" + feature.getVersion());
|
||||
}
|
||||
|
||||
// broadcast a cluster event
|
||||
ClusterRepositoryEvent event =
|
||||
new ClusterRepositoryEvent(url, RepositoryEvent.EventType.RepositoryRemoved);
|
||||
event.setUninstall(uninstall);
|
||||
event.setSourceGroup(group);
|
||||
event.setSourceNode(clusterManager.getNode());
|
||||
eventProducer.produce(event);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Features repository URL " + url + " not found in cluster group " + groupName);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void block(String groupName, String featurePattern, boolean whitelist, boolean blacklist, boolean in,
|
||||
boolean out) throws Exception {
|
||||
|
||||
Group group = groupManager.findGroupByName(groupName);
|
||||
if (group == null) {
|
||||
throw new IllegalArgumentException("Cluster group " + groupName + " doesn't exist");
|
||||
}
|
||||
|
||||
CellarSupport support = new CellarSupport();
|
||||
support.setClusterManager(clusterManager);
|
||||
support.setGroupManager(groupManager);
|
||||
support.setConfigurationAdmin(configurationAdmin);
|
||||
|
||||
if (in) {
|
||||
if (whitelist)
|
||||
support.switchListEntry(Configurations.WHITELIST, groupName, Constants.CATEGORY, EventType.INBOUND,
|
||||
featurePattern);
|
||||
if (blacklist)
|
||||
support.switchListEntry(Configurations.BLACKLIST, groupName, Constants.CATEGORY, EventType.INBOUND,
|
||||
featurePattern);
|
||||
}
|
||||
if (out) {
|
||||
if (whitelist)
|
||||
support.switchListEntry(Configurations.WHITELIST, groupName, Constants.CATEGORY, EventType.OUTBOUND,
|
||||
featurePattern);
|
||||
if (blacklist)
|
||||
support.switchListEntry(Configurations.BLACKLIST, groupName, Constants.CATEGORY, EventType.OUTBOUND,
|
||||
featurePattern);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ExtendedFeatureState extends FeatureState {
|
||||
|
||||
private boolean cluster;
|
||||
private boolean local;
|
||||
|
||||
public boolean isCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
public void setCluster(boolean cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public void setLocal(boolean local) {
|
||||
this.local = local;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.helper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.karaf.cellar.core.ClusterManager;
|
||||
import org.apache.karaf.cellar.core.GroupManager;
|
||||
import org.apache.karaf.cellar.core.event.EventProducer;
|
||||
import org.apache.karaf.cellar.features.management.CellarFeaturesMBean;
|
||||
import org.apache.karaf.features.FeaturesService;
|
||||
import org.osgi.service.cm.ConfigurationAdmin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class HelperFactory {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HelperFactory.class);
|
||||
|
||||
public static <T> T createHelper(Class<T> targetClass) {
|
||||
|
||||
return createHelper(targetClass, Collections.emptyMap());
|
||||
|
||||
}
|
||||
|
||||
public static <T> T createHelper(Class<T> targetClass, Map<Object, Object> parameters) {
|
||||
|
||||
if (CellarFeaturesMBean.class.equals(targetClass))
|
||||
return (T) createFeaturesHelper(parameters);
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected static CellarFeaturesHelper createFeaturesHelper(Map<Object, Object> parameters) {
|
||||
CellarFeaturesHelper result = new CellarFeaturesHelper();
|
||||
|
||||
if (parameters.containsKey(ClusterManager.class.getName()))
|
||||
result.setClusterManager((ClusterManager) parameters.get(ClusterManager.class.getName()));
|
||||
else if (Services.INSTANCE != null)
|
||||
result.setClusterManager(Services.INSTANCE.clusterManager);
|
||||
|
||||
if (parameters.containsKey(ConfigurationAdmin.class.getName()))
|
||||
result.setConfigurationAdmin((ConfigurationAdmin) parameters.get(ConfigurationAdmin.class.getName()));
|
||||
else if (Services.INSTANCE != null)
|
||||
result.setConfigurationAdmin(Services.INSTANCE.configurationAdmin);
|
||||
|
||||
if (parameters.containsKey(EventProducer.class.getName()))
|
||||
result.setEventProducer((EventProducer) parameters.get(EventProducer.class.getName()));
|
||||
else if (Services.INSTANCE != null)
|
||||
result.setEventProducer(Services.INSTANCE.eventProducer);
|
||||
|
||||
if (parameters.containsKey(FeaturesService.class.getName()))
|
||||
result.setFeaturesService((FeaturesService) parameters.get(FeaturesService.class.getName()));
|
||||
else if (Services.INSTANCE != null)
|
||||
result.setFeaturesService(Services.INSTANCE.featuresService);
|
||||
|
||||
if (parameters.containsKey(GroupManager.class.getName()))
|
||||
result.setGroupManager((GroupManager) parameters.get(GroupManager.class.getName()));
|
||||
else if (Services.INSTANCE != null)
|
||||
result.setGroupManager(Services.INSTANCE.groupManager);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.helper;
|
||||
|
||||
import org.apache.karaf.cellar.core.ClusterManager;
|
||||
import org.apache.karaf.cellar.core.GroupManager;
|
||||
import org.apache.karaf.cellar.core.event.EventProducer;
|
||||
import org.apache.karaf.features.FeaturesService;
|
||||
import org.osgi.service.cm.ConfigurationAdmin;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
|
||||
@Component(service = Services.class, immediate = true)
|
||||
public class Services {
|
||||
|
||||
public static Services INSTANCE = null;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
|
||||
public volatile ClusterManager clusterManager;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
|
||||
public volatile ConfigurationAdmin configurationAdmin;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
|
||||
public volatile EventProducer eventProducer;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
|
||||
public volatile FeaturesService featuresService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
|
||||
public volatile GroupManager groupManager;
|
||||
|
||||
@Activate
|
||||
public void activate() {
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.karaf.cellar.core.event.Event;
|
||||
|
||||
public class CellarSequenceEvent extends Event implements Serializable {
|
||||
|
||||
List<CellarSequenceItemEvent> sequence = new ArrayList<>();
|
||||
|
||||
boolean waitLast = true;
|
||||
|
||||
public CellarSequenceEvent(String sequenceId) {
|
||||
super(sequenceId);
|
||||
}
|
||||
|
||||
public List<CellarSequenceItemEvent> getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public boolean isWaitLast() {
|
||||
return waitLast;
|
||||
}
|
||||
|
||||
public void setWaitLast(boolean waitLast) {
|
||||
this.waitLast = waitLast;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence;
|
||||
|
||||
import org.apache.karaf.cellar.core.event.Event;
|
||||
|
||||
public class CellarSequenceItemEvent extends Event {
|
||||
|
||||
Event event;
|
||||
|
||||
// -1 - infinite
|
||||
// 0 - don't wait
|
||||
// x - time in mills
|
||||
int operationTimeout = -1;
|
||||
|
||||
public CellarSequenceItemEvent(String id, Event event) {
|
||||
super(id);
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
public int getOperationTimeout() {
|
||||
return operationTimeout;
|
||||
}
|
||||
|
||||
public void setOperationTimeout(int operationTimeout) {
|
||||
this.operationTimeout = operationTimeout;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence;
|
||||
|
||||
public interface CellarSequenceManager {
|
||||
|
||||
void releaseSequence(String sequenceId);
|
||||
|
||||
void produceSequence(String sequenceId);
|
||||
|
||||
<T> T getSequencedHelper(String sequenceId, Class<T> targetClass);
|
||||
|
||||
SequenceBuilder getSequence(String sequenceId);
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence;
|
||||
|
||||
import org.apache.karaf.cellar.core.control.BasicSwitch;
|
||||
import org.apache.karaf.cellar.core.control.Switch;
|
||||
import org.apache.karaf.cellar.core.event.Event;
|
||||
import org.apache.karaf.cellar.core.event.EventProducer;
|
||||
|
||||
public class SequenceBuilder<E extends Event> implements EventProducer<E> {
|
||||
|
||||
protected CellarSequenceEvent cellarSequenceEvent;
|
||||
|
||||
protected Switch eventSwitch = new BasicSwitch(getClass().getName());
|
||||
|
||||
public SequenceBuilder(String sequenceId) {
|
||||
super();
|
||||
this.cellarSequenceEvent = new CellarSequenceEvent(sequenceId);
|
||||
}
|
||||
|
||||
public CellarSequenceEvent getEvent() {
|
||||
return cellarSequenceEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Switch getSwitch() {
|
||||
return eventSwitch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void produce(Event event) {
|
||||
|
||||
cellarSequenceEvent.sequence.add(new CellarSequenceItemEvent(event.getId(), event));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.apache.karaf.cellar.core.control.BasicSwitch;
|
||||
import org.apache.karaf.cellar.core.control.Switch;
|
||||
import org.apache.karaf.cellar.core.event.EventHandler;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ru.entaxy.platform.runtime.cellar.sequence.process.SequenceTask;
|
||||
|
||||
@Component(service = EventHandler.class, immediate = true)
|
||||
public class SequenceEventHandler implements EventHandler<CellarSequenceEvent> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SequenceEventHandler.class);
|
||||
|
||||
protected Switch eventSwitch = new BasicSwitch(getClass().getName());
|
||||
|
||||
protected ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
@Override
|
||||
public Class<CellarSequenceEvent> getType() {
|
||||
return CellarSequenceEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Switch getSwitch() {
|
||||
return eventSwitch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CellarSequenceEvent event) {
|
||||
LOG.info("Received event: " + event.getId());
|
||||
threadPool.execute(new SequenceTask(event, Thread.currentThread().getContextClassLoader()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.karaf.cellar.core.event.EventProducer;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
|
||||
import ru.entaxy.platform.runtime.cellar.helper.HelperFactory;
|
||||
import ru.entaxy.platform.runtime.cellar.sequence.CellarSequenceManager;
|
||||
import ru.entaxy.platform.runtime.cellar.sequence.SequenceBuilder;
|
||||
|
||||
@Component(service = CellarSequenceManager.class, immediate = true)
|
||||
public class CellarSequenceManagerImpl implements CellarSequenceManager {
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC)
|
||||
protected volatile EventProducer eventProducer;
|
||||
|
||||
protected final Map<String, SequenceBuilder> sequences = new HashMap<>();
|
||||
protected Object sequencesLock = new Object();
|
||||
|
||||
@Override
|
||||
public <T> T getSequencedHelper(String sequenceId, Class<T> targetClass) {
|
||||
|
||||
Map<Object, Object> properties = new HashMap<>();
|
||||
properties.put(EventProducer.class.getName(), getSequenceBuilder(sequenceId));
|
||||
|
||||
return HelperFactory.createHelper(targetClass, properties);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void produceSequence(String sequenceId) {
|
||||
synchronized (sequencesLock) {
|
||||
if (sequences.containsKey(sequenceId))
|
||||
eventProducer.produce(sequences.get(sequenceId).getEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSequence(String sequenceId) {
|
||||
synchronized (sequencesLock) {
|
||||
sequences.remove(sequenceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequenceBuilder getSequence(String sequenceId) {
|
||||
return getSequenceBuilder(sequenceId);
|
||||
}
|
||||
|
||||
protected SequenceBuilder getSequenceBuilder(String sequenceId) {
|
||||
synchronized (sequencesLock) {
|
||||
if (!sequences.containsKey(sequenceId))
|
||||
sequences.put(sequenceId, new SequenceBuilder(sequenceId));
|
||||
return sequences.get(sequenceId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence.process;
|
||||
|
||||
public interface ChangeListener {
|
||||
|
||||
public interface CallBack {
|
||||
void success();
|
||||
|
||||
default void fail() {};
|
||||
|
||||
default void timeout() {};
|
||||
}
|
||||
|
||||
void setCallback(CallBack callBack);
|
||||
|
||||
void register();
|
||||
|
||||
void unregister();
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence.process;
|
||||
|
||||
import org.apache.karaf.cellar.core.event.Event;
|
||||
import org.apache.karaf.cellar.features.ClusterFeaturesEvent;
|
||||
import org.apache.karaf.cellar.features.ClusterRepositoryEvent;
|
||||
import org.apache.karaf.features.FeatureEvent;
|
||||
import org.apache.karaf.features.FeaturesListener;
|
||||
import org.apache.karaf.features.RepositoryEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ru.entaxy.platform.runtime.cellar.helper.Services;
|
||||
|
||||
public class ChangeListenerFactory {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChangeListenerFactory.class);
|
||||
|
||||
public static ChangeListener create(Event originEvent) {
|
||||
|
||||
if (originEvent instanceof ClusterRepositoryEvent) {
|
||||
return new RepositoryListener((ClusterRepositoryEvent) originEvent);
|
||||
}
|
||||
|
||||
if (originEvent instanceof ClusterFeaturesEvent) {
|
||||
return new FeatureListener((ClusterFeaturesEvent) originEvent);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static abstract class AbstractChangeListener<T extends Event> implements ChangeListener {
|
||||
|
||||
protected CallBack callBack;
|
||||
|
||||
protected T originEvent;
|
||||
|
||||
public AbstractChangeListener(T event) {
|
||||
super();
|
||||
this.originEvent = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(CallBack callBack) {
|
||||
this.callBack = callBack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class RepositoryListener extends AbstractChangeListener<ClusterRepositoryEvent>
|
||||
implements FeaturesListener {
|
||||
|
||||
public RepositoryListener(ClusterRepositoryEvent event) {
|
||||
super(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
Services.INSTANCE.featuresService.registerListener(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
Services.INSTANCE.featuresService.unregisterListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void featureEvent(FeatureEvent event) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repositoryEvent(RepositoryEvent event) {
|
||||
if (event.getRepository().getURI().toString().equals(originEvent.getId())) {
|
||||
if (originEvent.getType().equals(event.getType())) {
|
||||
LOG.debug("REPOSITORY EVENT for [{}]", originEvent.getId());
|
||||
callBack.success();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
protected static class FeatureListener extends AbstractChangeListener<ClusterFeaturesEvent>
|
||||
implements FeaturesListener {
|
||||
|
||||
public FeatureListener(ClusterFeaturesEvent event) {
|
||||
super(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
Services.INSTANCE.featuresService.registerListener(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
Services.INSTANCE.featuresService.unregisterListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void featureEvent(FeatureEvent event) {
|
||||
if (event.getFeature().getId().equals(originEvent.getId())) {
|
||||
if (originEvent.getType().equals(event.getType())) {
|
||||
LOG.debug("FEATURE EVENT for [{}]", originEvent.getId());
|
||||
callBack.success();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repositoryEvent(RepositoryEvent event) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,276 @@
|
||||
/*-
|
||||
* ~~~~~~licensing~~~~~~
|
||||
* cellar-extensions
|
||||
* ==========
|
||||
* Copyright (C) 2020 - 2025 EmDev LLC
|
||||
* ==========
|
||||
* You may not use this file except in accordance with the License Terms of the Copyright
|
||||
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
|
||||
* rights to the Software and any copies are the property of the Copyright Holder. Unless
|
||||
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
|
||||
* Software for commercial purposes to provide services to third parties.
|
||||
*
|
||||
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
|
||||
* Under no circumstances does the Copyright Holder guarantee or promise that the
|
||||
* Software provided by him will be suitable or not suitable for the specific purposes
|
||||
* of the User, that the Software will meet all commercial and personal subjective
|
||||
* expectations of the User, that the Software will work properly, without technical
|
||||
* errors, quickly and uninterruptedly.
|
||||
*
|
||||
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
|
||||
* to the User for any direct or indirect losses of the User, his expenses or actual
|
||||
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
|
||||
* or damage to data, property, etc.
|
||||
* ~~~~~~/licensing~~~~~~
|
||||
*/
|
||||
package ru.entaxy.platform.runtime.cellar.sequence.process;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.karaf.cellar.core.event.Event;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ru.entaxy.platform.runtime.cellar.helper.Services;
|
||||
import ru.entaxy.platform.runtime.cellar.sequence.CellarSequenceEvent;
|
||||
import ru.entaxy.platform.runtime.cellar.sequence.CellarSequenceItemEvent;
|
||||
|
||||
public class SequenceTask implements Runnable, ChangeListener.CallBack {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SequenceTask.class);
|
||||
|
||||
protected enum EVENT_RESULT {
|
||||
NONE,
|
||||
SUCCESS,
|
||||
ERROR,
|
||||
TIMEOUT
|
||||
}
|
||||
|
||||
protected CellarSequenceEvent sequence;
|
||||
|
||||
protected ArrayDeque<CellarSequenceItemEvent> events;
|
||||
|
||||
protected Object eventsLock = new Object();
|
||||
|
||||
protected CellarSequenceItemEvent currentEvent;
|
||||
|
||||
protected ChangeListener currentChangeListener;
|
||||
|
||||
protected Object currentChangeListenerLock = new Object();
|
||||
|
||||
protected ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
protected Future<Object> future;
|
||||
|
||||
protected Object futureLock = new Object();
|
||||
|
||||
protected EVENT_RESULT currentResult;
|
||||
|
||||
protected Object currentResultLock = new Object();
|
||||
|
||||
public SequenceTask(CellarSequenceEvent event, ClassLoader classLoader) {
|
||||
super();
|
||||
this.sequence = event;
|
||||
events = new ArrayDeque<>(this.sequence.getSequence());
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
LOG.debug("\n--> CREATED SequenceTask for [{}]", sequence.getId());
|
||||
}
|
||||
|
||||
protected void updateCurrentResult(EVENT_RESULT newResult) {
|
||||
synchronized (currentResultLock) {
|
||||
LOG.debug("\n--> CURRENT RESULT set to [{}]", newResult.name());
|
||||
this.currentResult = newResult;
|
||||
}
|
||||
}
|
||||
|
||||
protected void resetResult() {
|
||||
updateCurrentResult(EVENT_RESULT.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
LOG.debug("\n--> RUNNING SequenceTask for [{}]", sequence.getId());
|
||||
|
||||
resetResult();
|
||||
|
||||
// global limit for operation = 5 min
|
||||
long maxExecution = 300000;
|
||||
long executionStep = 500;
|
||||
|
||||
while (!events.isEmpty()) {
|
||||
next();
|
||||
long executionPeriod = 0;
|
||||
while (EVENT_RESULT.NONE.equals(currentResult) && (executionPeriod < maxExecution)) {
|
||||
try {
|
||||
LOG.debug("\n--> WAITING FOR RESULT [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
executionPeriod += executionStep;
|
||||
Thread.sleep(executionStep);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.debug("\n--> INTERRUPTED WAITING FOR RESULT [{}]",
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
updateCurrentResult(EVENT_RESULT.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// maxExecution reached
|
||||
if (EVENT_RESULT.NONE.equals(currentResult)) {
|
||||
LOG.debug("\n--> CURRENT RESULT is NONE for [{}]",
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
updateCurrentResult(EVENT_RESULT.ERROR);
|
||||
}
|
||||
|
||||
if (EVENT_RESULT.SUCCESS.equals(currentResult)) {
|
||||
LOG.debug("\n--> CURRENT RESULT is SUCCESS for [{}]",
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
resetResult();
|
||||
} else {
|
||||
LOG.debug("\n--> CURRENT RESULT is [{}] for [{}]",
|
||||
currentResult == null ? "null" : currentResult.name(),
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
LOG.error("Failed processing sequence event");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean haveToWait() {
|
||||
if (events.isEmpty() && !sequence.isWaitLast())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void next() {
|
||||
synchronized (eventsLock) {
|
||||
LOG.debug("\n--> NEXT event");
|
||||
currentEvent = null;
|
||||
currentChangeListener = null;
|
||||
|
||||
if (events.isEmpty())
|
||||
return;
|
||||
|
||||
currentEvent = events.pop();
|
||||
LOG.debug("\n--> CURRENT event is [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
|
||||
if (haveToWait()) {
|
||||
|
||||
LOG.debug("\n--> WILL WAIT for result for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
|
||||
currentChangeListener = ChangeListenerFactory.create(currentEvent.getEvent());
|
||||
if (currentChangeListener == null) {
|
||||
updateCurrentResult(EVENT_RESULT.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
currentChangeListener.setCallback(this);
|
||||
currentChangeListener.register();
|
||||
|
||||
Callable<Object> task = new Callable<Object>() {
|
||||
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
Event eventToSend = currentEvent.getEvent();
|
||||
eventToSend.setDestination(Collections.singleton(Services.INSTANCE.clusterManager.getNode()));
|
||||
|
||||
LOG.debug("\n--> EVENT SENT: [{}]:[{}]", eventToSend.getClass().getName(), eventToSend.getId());
|
||||
Services.INSTANCE.eventProducer.produce(eventToSend);
|
||||
|
||||
// timeout for operation
|
||||
// Thread.sleep(100000);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
future = threadPool.submit(task);
|
||||
try {
|
||||
Object result = future.get(100, TimeUnit.SECONDS);
|
||||
LOG.debug("\n--> RESULT RECEIVED for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
} catch (TimeoutException timeoutEx) {
|
||||
LOG.debug("\n--> TimeoutException for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
updateCurrentResult(EVENT_RESULT.TIMEOUT);
|
||||
unregisterChangeListener();
|
||||
} catch (InterruptedException ignore) {
|
||||
// NOOP
|
||||
LOG.debug("\n--> InterruptedException for [{}]",
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
} catch (CancellationException ignore) {
|
||||
// NOOP
|
||||
LOG.debug("\n--> CancellationException for [{}]",
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
} catch (Exception e) {
|
||||
LOG.debug("\n--> Exception for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
LOG.error("Exception on next event processing", e);
|
||||
updateCurrentResult(EVENT_RESULT.ERROR);
|
||||
unregisterChangeListener();
|
||||
} finally {
|
||||
// unregisterChangeListener();
|
||||
}
|
||||
} else {
|
||||
LOG.debug("\n--> WILL NOT WAIT for result for [{}]",
|
||||
currentEvent == null ? "null" : currentEvent.getId());
|
||||
|
||||
threadPool.execute(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Event eventToSend = currentEvent.getEvent();
|
||||
eventToSend.setDestination(Collections.singleton(Services.INSTANCE.clusterManager.getNode()));
|
||||
Services.INSTANCE.eventProducer.produce(eventToSend);
|
||||
LOG.debug("\n--> EVENT SENT: [{}]:[{}]", eventToSend.getClass().getName(), eventToSend.getId());
|
||||
}
|
||||
});
|
||||
updateCurrentResult(EVENT_RESULT.SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void unregisterChangeListener() {
|
||||
synchronized (currentChangeListenerLock) {
|
||||
if (currentChangeListener != null)
|
||||
currentChangeListener.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void success() {
|
||||
LOG.debug("\n--> CALLED 'success' for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
synchronized (futureLock) {
|
||||
if (this.future != null)
|
||||
future.cancel(true);
|
||||
}
|
||||
unregisterChangeListener();
|
||||
updateCurrentResult(EVENT_RESULT.SUCCESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeout() {
|
||||
LOG.debug("\n--> CALLED 'timeout' for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
synchronized (futureLock) {
|
||||
if (this.future != null)
|
||||
future.cancel(true);
|
||||
}
|
||||
unregisterChangeListener();
|
||||
updateCurrentResult(EVENT_RESULT.TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail() {
|
||||
LOG.debug("\n--> CALLED 'fail' for [{}]", currentEvent == null ? "null" : currentEvent.getId());
|
||||
synchronized (futureLock) {
|
||||
if (this.future != null)
|
||||
future.cancel(true);
|
||||
}
|
||||
unregisterChangeListener();
|
||||
updateCurrentResult(EVENT_RESULT.ERROR);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user