diff --git a/documentation/Management layer.postman_collection.json b/documentation/Management layer.postman_collection.json
index b2669b09..3dafc221 100644
--- a/documentation/Management layer.postman_collection.json
+++ b/documentation/Management layer.postman_collection.json
@@ -1897,7 +1897,7 @@
"system-management"
]
},
- "description": "Создать сразу несколько доступов, которым разрешено отправлять сообщения от данной системы, можно с помощью метода сreatePermissionForObjectRequest, где “objectUuid” это uuid системы, от которой буду исходить сообщения, ‘“subjectUuid1”, “subjectUuid2” и т д, это uuid систем, которым будут отправлять сообщения\n"
+ "description": "Создать сразу несколько доступов, которым разрешено отправлять сообщения от данной системы, можно с помощью метода createPermissionForObjectRequest, где “objectUuid” это uuid системы, от которой буду исходить сообщения, ‘“subjectUuid1”, “subjectUuid2” и т д, это uuid систем, которым будут отправлять сообщения\n"
},
"response": []
},
@@ -1979,7 +1979,7 @@
"system-management"
]
},
- "description": "Создать сразу несколько доступов, которым разрешено отправлять сообщения в данную систему, можно с помощью метода сreatePermissionForSubjectRequest, где “objectUuid1”, “objectUuid2” и т д - это uuid систем, от которых буду исходить сообщения, ‘“subjectUuid” - это uuid системы, которой будут отправлять сообщения\n"
+ "description": "Создать сразу несколько доступов, которым разрешено отправлять сообщения в данную систему, можно с помощью метода createPermissionForSubjectRequest, где “objectUuid1”, “objectUuid2” и т д - это uuid систем, от которых буду исходить сообщения, ‘“subjectUuid” - это uuid системы, которой будут отправлять сообщения\n"
},
"response": []
}
@@ -2973,7 +2973,7 @@
"schema"
]
},
- "description": "Для корректирования мета информации ресурса в шине есть метод еditResourceInfo.\n\n\n\n\n"
+ "description": "Для корректирования мета информации ресурса в шине есть метод editResourceInfo.\n\n\n\n\n"
},
"response": []
},
diff --git a/documentation/core/topic/Topic-management-Rest-service.adoc b/documentation/core/topic/Topic-management-Rest-service.adoc
index 8bf75929..33b82fbd 100644
--- a/documentation/core/topic/Topic-management-Rest-service.adoc
+++ b/documentation/core/topic/Topic-management-Rest-service.adoc
@@ -64,7 +64,7 @@ redelivery.redeliveryDelay=5000
#cron - по умолчанию запускается каждые 00:00:00,
#cron выражение использует знак "+" как разделитель для модуля quartz2l
-quirtz.job.clean.cron=0+0+0+*+*+?+*
+quartz.job.clean.cron=0+0+0+*+*+?+*
----
- _ru.entaxy.esb.system.event.rest.cfg_
@@ -550,6 +550,6 @@ _POST server:9090/topic-subscription/publish_
Т.к. удаление топиков происходит в 2 этапа, с помощью планировщика _Quartz2_, работающего в кластере, запускается задача по очистке. Запуск происходит в конкурентном режиме, узел первый запустивший задачу получает приоритет, на остальных узлах задача останавливается до следующего запуска.
-Частота запуска задачи настраивается в конфигурационном файле _ru.entaxy.esb.system.event.handler.cfg_ в свойстве quirtz.job.clean.cron=0+0+0+*+*+?+*
+Частота запуска задачи настраивается в конфигурационном файле _ru.entaxy.esb.system.event.handler.cfg_ в свойстве quartz.job.clean.cron=0+0+0+*+*+?+*
с помощью cron выражения. Особенность cron выражения для quartz в том что “++” используется, как разделитель.
diff --git a/documentation/extras/eav.adoc b/documentation/extras/eav.adoc
new file mode 100644
index 00000000..2d23c1b7
--- /dev/null
+++ b/documentation/extras/eav.adoc
@@ -0,0 +1,171 @@
+= Хранилище данных EAV
+
+== Описание модуля EXTRAS :: ENTAXY :: EAV (Entity, Attribute, Value)
+
+Хранилище данных EAV реализует модель _Сущность-Атрибут-Значение_ - это модель данных, предназначенная для описания сущностей, в которых количество атрибутов (свойств, параметров) не ограничено или не известно заранее.
+
+
+== Объекты модуля ЕАV
+
+image::eav_objects.png[]
+
+*Внешняя сущность*(External Entity) - любая внешняя сущность относительно модуля EAV.
+
+*Сущность EAV*(Entity EAV) - именованная сущность, связывающая аттрибуты с внешней сущностью.
+ Модуль предоставляет возможность объединять сущности EAV в одноуровневую иерархию.
+
+*Атрибут*(Attribute) - именованный атрибут сущности EAV, содержит значение и его тип.
+
+*Типы значений:*
+
+* DOUBLE
+* LONG
+* TEXT
+* JSON
+
+
+
+
+== Использование хранилища EAV
+
+В BLUEPRINT подключаем OSGI-сервис EAVProcessor
+[source]
+----
+
+----
+
+в маршрутах или java коде осуществляем необходимые вызовы для создания/получения/изменения значений.
+
+*Примеры вызовов из маршрута Apache Camel XMLDSL*
+
+Создание атрибута для внешней сущности
+[source]
+----
+
+----
+
+Получить все значения сохранённой сущности
+[source]
+----
+
+----
+
+Удалить сохранённые значения
+[source]
+----
+
+----
+
+
+
+== OSGI-сервис EAVProcessor.
+Сервис, выставляющий api для работы с EAV хранилищем.
+
+
+
+*Методы:*
+
+* _createPrimitive_ - простой метод сохранения примитивного значения(числового, строкового)
+* _createComplex_ - простой метод сохранения комплексного значения(JSON)
+* _getEntityWithValues_ - получение значений сущности EAV по имени
+* _fetchEntityWithValues_ - получение значений сущности EAV по имени либо null, без исключений
+* _getEntityNamedAttributes_ - получение значений с определённым именем для сущности EAV
+* _getEntityByNameAndAttributeValue_ - получение сущности EAV по атрибуту
+* _getParentEntity_ - получение родительской сущности EAV для внешней связанной сущности
+* _getChildEntities_ - получение дочерних сущностей EAV для внешней связанной сущности с именем сущности EAV по умолчанию(PARENT)
+* _getChildEntitiesByName_ - получение дочерних сущностей EAV для внешней связанной сущности с указанным именем сущности EAV
+* _getByExternalEntity_ - получение всех сущностей EAV для внешней связанной сущности
+* _getByAttributeSet_ - получение сущностей EAV по множественным наборов параметров, каждый набор составляется из значений элементов с одним порядковым номером всех списков
+* _updateAttribute_ - метод для изменения значения аттрибута
+* _deleteExternalEntity_ - удаление всех записей связанных с внешней сущностью
+* _deleteEntity_ - удаление именованной сущности EAV
+* _deleteAllEntityAttributes_ - удаление атрибутов именованной сущности EAV
+* _deleteAllEntityAttributesByName_ - удаление аттрибута сущности EAV с определённым наименованием
+* _combineEntities_ - метод для объединения внешних сущностей под 1 родителем
+
+
+
+== Схема базы данных(БД).
+
+Схема БД при таком подходе остаётся неизменной независимо от состава и структуры хранимых данных.
+Бандл eav-storage разворачивает структуру из 2 таблиц:
+
+*Таблица eav_entity*
+|===
+|Слолбец |Параметры |Описание
+//----------------------
+|id
+|bigint, not null
+|идентификатор сущности модуля EAV
+
+|external_id
+|text, not null
+|внешний идентификатор связываемой сущности
+
+|external_type
+|text, not null
+|тип связываемой сущности
+
+|name
+|text
+|наименование сущности модуля EAV
+
+|parent_id
+|bigint, not null, default 0
+|идентификатор(поле id) родительской сущности модуля EAV
+
+|create_date
+|timestamp, not null
+|служебное поле, дата создания
+
+|edit_date
+|timestamp
+|служебное поле, дата изменения
+
+|created_by
+|text, not null
+|служебное поле, логин автора записи
+
+|external_type
+|text
+|служебное поле, логин последнего изменившего сущность
+|===
+
+
+*Таблица eav_attribute*
+|===
+|Слолбец |Параметры |Описание
+//----------------------
+|id
+|bigint, not null
+|идентификатор атрибута
+
+|entity_id
+|text, not null
+|идентификатор сущности eav_entity
+
+|name
+|text, not null
+|наименование аттрибута
+
+|type
+|text
+|тип аттрибута
+
+|double
+|double
+|служебное поле для хранения значения
+
+|long
+|bigint
+|служебное поле для хранения значения
+
+|text
+|text
+|служебное поле для хранения значения
+
+|text2
+|text
+|служебное поле для хранения значения
+
+|===
\ No newline at end of file
diff --git a/documentation/extras/eav_objects.png b/documentation/extras/eav_objects.png
new file mode 100644
index 00000000..bab4d67c
Binary files /dev/null and b/documentation/extras/eav_objects.png differ
diff --git a/documentation/index.adoc b/documentation/index.adoc
index e2ce5fff..ed0cf6d8 100644
--- a/documentation/index.adoc
+++ b/documentation/index.adoc
@@ -18,8 +18,8 @@ _Для разработчиков:
-имеет Api, который занимается Crud операциями,
-хранит учетные записи в базе данных,
-предоставляет файл с актуальной информацией для nginx,
--выставляет interсeptor для аутентификации в других сервисах,
--выставляет interсeptor для определения принадлежности аккаунта определённой системе._
+-выставляет interceptor для аутентификации в других сервисах,
+-выставляет interceptor для определения принадлежности аккаунта определённой системе._
=== permission
@@ -32,7 +32,7 @@ _Для разработчиков:
-имеет Api, который занимается Crud операциями
- хранит права в базе данных,
-(camel)компонент, который используется в маршрутах, для проверки возможности отправки из системы a в систему b.
--выставляет interсeptor для авторизации в служебных сервисах._
+-выставляет interceptor для авторизации в служебных сервисах._
=== system-management-api
diff --git a/documentation/installation/local-installation/local-installation.ru.adoc b/documentation/installation/local-installation/local-installation.ru.adoc
index 94fda996..496675e6 100644
--- a/documentation/installation/local-installation/local-installation.ru.adoc
+++ b/documentation/installation/local-installation/local-installation.ru.adoc
@@ -21,7 +21,7 @@ __Alternative languages:__
== Дистрибутивы Entaxy
-Сущетсвет несколько вариантов сборок Entaxy, которые доступны по адресу https://entaxy.ru/download
+Существует несколько вариантов сборок Entaxy, которые доступны по адресу https://entaxy.ru/download
. `entaxy-assembly-compact*` - все-в-одном, брокер, бд и графический веб-интерфейс в одной сборке. См. xref:#_установка_all_in_one [Установка all-in-one]
diff --git a/platform/pom.xml b/platform/pom.xml
index 3f84068f..c15d61a8 100644
--- a/platform/pom.xml
+++ b/platform/pom.xml
@@ -5,7 +5,7 @@
root
ru.entaxy.esb
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/base-support/pom.xml b/platform/runtime/base/base-support/pom.xml
index 5df74f57..ff2ccea6 100644
--- a/platform/runtime/base/base-support/pom.xml
+++ b/platform/runtime/base/base-support/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime
base
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.base
base-support
@@ -17,6 +17,7 @@
ru.entaxy.platform.base.support.xml,
ru.entaxy.platform.base.support.osgi,
ru.entaxy.platform.base.support.osgi.tracker,
+ ru.entaxy.platform.base.support.osgi.tracker.filter,
ru.entaxy.platform.base.support.osgi.filter
diff --git a/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/DependencySorter.java b/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/DependencySorter.java
new file mode 100644
index 00000000..8b8b7739
--- /dev/null
+++ b/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/DependencySorter.java
@@ -0,0 +1,54 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.support;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class DependencySorter {
+
+ public static interface DependencyProvider {
+ List getDependencies(T inspectedObject);
+ }
+
+ public static List getSortedList(List origin, DependencyProvider provider) throws Exception {
+ List result = new LinkedList<>();
+
+ // add independent objects
+ result.addAll(
+ origin.stream().filter(obj -> provider.getDependencies(obj).isEmpty())
+ .collect(Collectors.toList())
+ );
+
+ while (result.size() < origin.size()) {
+ List nextObjects = origin.stream().filter(obj->!result.contains(obj))
+ .filter(obj->result.containsAll(provider.getDependencies(obj)))
+ .collect(Collectors.toList());
+ if (nextObjects.isEmpty())
+ // TODO create more informative exception
+ throw new Exception("Contains unsatisfied dependencies");
+ result.addAll(nextObjects);
+ }
+
+ return result;
+ }
+
+}
diff --git a/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/FileUtils.java b/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/FileUtils.java
index cb83b297..0dddc8a8 100644
--- a/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/FileUtils.java
+++ b/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/FileUtils.java
@@ -39,7 +39,7 @@ public class FileUtils {
protected String md5FilePath = "";
protected String currentMd5 = null;
- protected String timmestampFilePath = "";
+ protected String timestampFilePath = "";
protected String currentTimestamp = null;
public FileHelper(String filePath) {
@@ -49,7 +49,7 @@ public class FileUtils {
public FileHelper(File file) {
this.file = file;
this.md5FilePath = file.getAbsolutePath().concat(".md5");
- this.timmestampFilePath = file.getAbsolutePath().concat(".timestamp");
+ this.timestampFilePath = file.getAbsolutePath().concat(".timestamp");
}
public boolean isReadable() {
@@ -59,7 +59,7 @@ public class FileUtils {
protected String calcMd5() {
if (!CommonUtils.isValid(this.fileMd5Hash))
try {
- this.fileMd5Hash = DigestUtils.md2Hex(this.file.toURI().toURL().openStream());
+ this.fileMd5Hash = DigestUtils.md5Hex(this.file.toURI().toURL().openStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -85,7 +85,7 @@ public class FileUtils {
public String getTimestamp() {
if (this.currentTimestamp == null)
try {
- this.currentTimestamp = Files.readString((new File(this.timmestampFilePath)).toPath());
+ this.currentTimestamp = Files.readString((new File(this.timestampFilePath)).toPath());
} catch (IOException e) {
this.currentTimestamp = "";
}
@@ -121,7 +121,7 @@ public class FileUtils {
String timestamp = Calendar.getInstance().getTimeInMillis() + "";
String result = "";
try {
- FileUtils.string2file(timestamp, timmestampFilePath);
+ FileUtils.string2file(timestamp, timestampFilePath);
this.currentTimestamp = null;
result = getTimestamp();
} catch (IOException e) {
diff --git a/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/JSONUtils.java b/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/JSONUtils.java
index 9eb9a67f..fceecb9d 100644
--- a/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/JSONUtils.java
+++ b/platform/runtime/base/base-support/src/main/java/ru/entaxy/platform/base/support/JSONUtils.java
@@ -1,5 +1,4 @@
-/*-
- * ~~~~~~licensing~~~~~~
+/* ~~~~~~licensing~~~~~~
* base-support
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
@@ -25,10 +24,12 @@ import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.stream.Collectors;
import com.google.gson.JsonArray;
@@ -108,10 +109,283 @@ public class JSONUtils {
url.openStream(), StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
+ return JSONUtils.getJsonRootObject(metadata);
+ }
+
+ public static JsonObject getJsonRootObject(String jsonData) {
+ try {
+ JsonElement je = (new JsonParser()).parse(jsonData);
+ JsonObject root = je.getAsJsonObject();
+ return root;
+ } catch (Exception e) {
+ return new JsonObject();
+ }
+ }
+
+ public static void mergeObjects(JsonObject source, JsonObject target) {
+ if (source == null)
+ return;
+ if (target == null)
+ return;
+ for (Entry entry: source.entrySet()) {
+ if (target.has(entry.getKey())) {
+ if (entry.getValue().isJsonObject())
+ if (target.get(entry.getKey()).isJsonObject()) {
+ mergeObjects(entry.getValue().getAsJsonObject(), target.get(entry.getKey()).getAsJsonObject());
+ continue;
+ }
+ target.remove(entry.getKey());
+ }
+ target.add(entry.getKey(), entry.getValue().deepCopy());
+ }
+ }
+
+ public static boolean replaceValue(JsonObject origin, String path, JsonElement replacement) {
+ return setValue(origin, path, replacement, false);
+ }
+
+ public static boolean setValue(JsonObject origin, String path, JsonElement replacement, boolean ifMissing) {
+ String preparedPath = path.replaceAll("(\\[\\d+\\])", ".$1");
+ String[] pathSplitted = preparedPath.split("\\.");
+ JsonElement currentElement = origin;
+ for (int i=0; iindex)
+ currentElement = arr.get(index);
+ else {
+ // TODO process
+ // System.out.println("ERROR: index out of bounds");
+ }
+ } else {
+ // TODO process
+ // System.out.println("ERROR: found indexed property on non-array value");
+ }
+ } else if (currentElement.isJsonObject()) {
+ currentElement = currentElement.getAsJsonObject().get(fragment);
+ } else {
+ // TODO process
+ // System.out.println("ERROR: currentElement can't be traversed");
+ }
+ }
+ if (currentElement == null) {
+ // System.out.println("ERROR: currentElement is null");
+ return false;
+ }
+ String finalFragment = pathSplitted[pathSplitted.length-1];
+ if (finalFragment.startsWith("[") && finalFragment.endsWith("]")) {
+ // array index
+ if (currentElement.isJsonArray()) {
+ // System.out.println("INDEX: [" + finalFragment.substring(1, finalFragment.length()-1) + "]");
+ int index = Integer.parseInt(finalFragment.substring(1, finalFragment.length()-1));
+ JsonArray arr = currentElement.getAsJsonArray();
+ if (arr.size()>index) {
+ // arr.remove(index);
+ arr.set(index, replacement);
+ } else {
+ // TODO process
+ // System.out.println("ERROR: index out of bounds");
+ }
+ } else {
+ // TODO process
+ // System.out.println("ERROR: found indexed property on non-array value");
+ }
+ } else if (currentElement.isJsonObject()) {
+ if (ifMissing && currentElement.getAsJsonObject().has(finalFragment))
+ return false;
+ currentElement.getAsJsonObject().remove(finalFragment);
+ currentElement.getAsJsonObject().add(finalFragment, replacement);
+ } else {
+ // System.out.println("ERROR: currentElement can't be traversed");
+ return false;
+ }
+
+ // System.out.println("\n -- found --\n" + currentElement.toString() + "\n");
+ return true;
+ }
+
+ public static class JsonTraverse {
+
+ List checkers = new ArrayList<>();
+
+ public JsonTraverse checker(ObjectChecker checker) {
+ this.checkers.add(checker);
+ return this;
+ }
+
+ public Object traverse(JsonObject rootObject) {
+ Object result = null;
+
+ Map context = new HashMap<>();
+
+ result = element2object(rootObject, context, "$");
+
+ return result;
+ }
+
+ protected Object element2object(JsonElement element, Map context, String path) {
+ if (element.isJsonNull() || element.isJsonPrimitive())
+ return element2value(element, context, path);
+ if (element.isJsonArray())
+ return element2list(element, context, path);
+ if (element.isJsonObject()) {
+ JsonObject jsonObject = element.getAsJsonObject();
+ ObjectWrapper ow = null;
+ for (ObjectChecker oc: checkers) {
+ ow = oc.checkObject(jsonObject);
+ if (ow != null)
+ break;
+ }
+
+ if (ow != null) {
+ ow.wrap(jsonObject, context, path);
+ if (ow.continueTraverse())
+ ow.setTraverseMap(element2map(element, context, path), context);
+ return ow;
+ }
+
+ return element2map(element, context, path);
+ }
+ return null;
+ }
+
+ protected Map element2map(JsonElement element, Map context, String path){
+ Map result = new HashMap<>();
+ if (element.isJsonObject()) {
+ JsonObject jsonObject = element.getAsJsonObject();
+ for (Entry entry: jsonObject.entrySet()) {
+ result.put(entry.getKey(), element2object(entry.getValue(), context, path + "." + entry.getKey()));
+ }
+ } else
+ if (element.isJsonArray()) {
+ JsonArray array = element.getAsJsonArray();
+ result.put(PROP_VALUE, element2list(element, context, path));
+ } else
+ if (element.isJsonNull()) {
+ result.put(PROP_VALUE, null);
+ } else
+ if (element.isJsonPrimitive()) {
+ result.put(PROP_VALUE, element2value(element, context, path));
+ }
+
+ return result;
+ }
+
+ protected Object element2value(JsonElement element, Map context, String path) {
+ Object result = null;
+ if (element.isJsonNull() || !element.isJsonPrimitive())
+ return result;
+ try {
+ JsonPrimitive primitive = element.getAsJsonPrimitive();
+ if (primitive.isNumber())
+ result = primitive.getAsNumber();
+ else if (primitive.isBoolean())
+ result = primitive.getAsBoolean();
+ else result = primitive.getAsString();
+ } catch (Exception e1) {
+ try {
+ result = element.getAsBoolean();
+ } catch (Exception e2) {
+ result = element.getAsString();
+ }
+ }
+ return result;
+ }
+
+ protected List element2list(JsonElement element, Map context, String path) {
+ List result = new ArrayList<>();
+ JsonArray array = element.getAsJsonArray();
+ for (int i=0; i {
+
+ protected Map data = new HashMap<>();
+
+ public abstract void wrap(JsonObject object, Map context, String path);
+
+ public boolean continueTraverse() {
+ return true;
+ }
+
+ public void setTraverseMap(Map traverseMap, Map context) {
+ this.data = traverseMap;
+ }
+
+ @Override
+ public int size() {
+ return this.data.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.data.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return this.data.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return this.data.containsValue(value);
+ }
+
+ @Override
+ public Object get(Object key) {
+ return this.data.get(key);
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ return this.data.put(key, value);
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return this.data.remove(key);
+ }
+
+ @Override
+ public void putAll(Map extends String, ? extends Object> m) {
+ this.data.putAll(m);
+ }
+
+ @Override
+ public void clear() {
+ this.data.clear();
+ }
+
+ @Override
+ public Set keySet() {
+ return this.data.keySet();
+ }
+
+ @Override
+ public Collection values() {
+ return this.data.values();
+ }
+
+ @Override
+ public Set> entrySet() {
+ return this.data.entrySet();
+ };
- JsonElement je = (new JsonParser()).parse(metadata);
- JsonObject root = je.getAsJsonObject();
- return root;
}
}
diff --git a/platform/runtime/base/branding/pom.xml b/platform/runtime/base/branding/pom.xml
index 3d2fd6eb..6c9831aa 100644
--- a/platform/runtime/base/branding/pom.xml
+++ b/platform/runtime/base/branding/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime
base
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/config-extensions/LICENSE.txt b/platform/runtime/base/config-extensions/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/base/config-extensions/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/base/config-extensions/pom.xml b/platform/runtime/base/config-extensions/pom.xml
new file mode 100644
index 00000000..98a47320
--- /dev/null
+++ b/platform/runtime/base/config-extensions/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime
+ base
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.base
+ config-extensions
+ bundle
+ ENTAXY :: PLATFORM :: BASE :: CONFIG EXTENSIONS
+ ENTAXY :: PLATFORM :: BASE :: CONFIG EXTENSIONS
+
+
+ ru.entaxy.platform.base.config
+
+
+
+
+ org.apache.karaf.config
+ org.apache.karaf.config.core
+ ${karaf.version}
+
+
+ ru.entaxy.esb.platform.runtime.base
+ base-support
+ ${project.version}
+
+
+ org.apache.felix
+ org.apache.felix.configadmin
+ ${felix.configadmin.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ConfigLookupConfigurationPlugin.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ConfigLookupConfigurationPlugin.java
new file mode 100644
index 00000000..8d8be5c7
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ConfigLookupConfigurationPlugin.java
@@ -0,0 +1,105 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * config-plugin
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationPlugin;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * Configuration plugin providing resolving references from one config to others
+ * in a form $PID_OF_OTHER_CONFIG{PROPERTY_NAME}
+ * e.g. $org.ops4j.pax.url.mvn{org.ops4j.pax.url.mvn.localRepository}
+ *
+ * If pid or property not found no changes are made
+ *
+ * @author sstarovoytenkov
+ *
+ */
+@Component(service = {ConfigurationPlugin.class}, immediate = true,
+ property = {ConfigurationPlugin.CM_TARGET + "=*"
+ , ConfigurationPlugin.CM_RANKING + "=100"
+ , "config.plugin.id=ConfigLookupConfigurationPlugin"})
+public class ConfigLookupConfigurationPlugin implements ConfigurationPlugin {
+
+ private static final Logger log = LoggerFactory.getLogger(ConfigLookupConfigurationPlugin.class);
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ConfigurationAdmin configurationAdmin;
+
+ @Override
+ public void modifyConfiguration(ServiceReference> arg0, Dictionary properties) {
+ for (Enumeration keys = properties.keys(); keys.hasMoreElements(); ) {
+ String key = keys.nextElement();
+ Object val = properties.get(key);
+ if (val instanceof String) {
+
+ String text = (String)val;
+ String newValue = (String)val;
+ Pattern pattern = Pattern.compile("\\$([^\\{\\}])+\\{.+?\\}");
+ Matcher matcher = pattern.matcher(text);
+ while (matcher.find()) {
+ log.debug("FOUND :: " + text.substring(matcher.start(), matcher.end()));
+ String placeholder = text.substring(matcher.start(), matcher.end());
+ String pid = placeholder.substring(1, placeholder.indexOf("{"));
+ String propName = placeholder.substring(placeholder.indexOf("{")+1
+ , placeholder.indexOf("}"));
+ log.debug("PARSED :: " + pid + ":" + propName);
+ Configuration conf;
+ try {
+ conf = configurationAdmin.getConfiguration(pid);
+ if (conf != null) {
+
+ Dictionary props = conf.getProperties();
+ Object value = props.get(propName);
+ log.debug("VALUE :: " + placeholder + " = " + value);
+ if (value != null) {
+ newValue = newValue.replace(placeholder, (String)value);
+ log.debug("NEW VALUE :: " + placeholder + " = " + newValue);
+ }
+
+
+ }
+ } catch (IOException e) {
+ log.error("Error with pid: " + pid, e);
+ }
+
+ }
+
+ properties.put(key, newValue);
+
+ }
+ }
+ }
+
+}
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/DefaultPropertiesProvider.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/DefaultPropertiesProvider.java
new file mode 100644
index 00000000..8e0660ff
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/DefaultPropertiesProvider.java
@@ -0,0 +1,232 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * configuration-test-1
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.utils.properties.TypedProperties;
+import org.apache.karaf.config.core.ConfigRepository;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+
+public class DefaultPropertiesProvider implements Map {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultPropertiesProvider.class);
+
+ protected String objectId;
+
+ protected String objectType;
+
+
+ protected String configurationPid;
+ protected BundleContext bundleContext;
+ protected Map properties;
+
+ public DefaultPropertiesProvider(String configurationPid
+ , BundleContext bundleContext
+ , Map properties) {
+
+ this.configurationPid = configurationPid;
+ this.bundleContext = bundleContext;
+ this.properties = properties;
+ register();
+ }
+
+ public DefaultPropertiesProvider(String objectId
+ , String objectType
+ , String configurationPid
+ , BundleContext bundleContext
+ , Map properties) {
+
+ this.objectId = objectId;
+ this.objectType = objectType;
+
+ this.configurationPid = configurationPid;
+ this.bundleContext = bundleContext;
+ this.properties = properties;
+ register();
+ }
+
+ protected void register() {
+ if (!CommonUtils.isValid(objectId) || !CommonUtils.isValid(objectType))
+ return;
+ try {
+ String fileName = System.getProperty("karaf.etc");
+ Path path = Paths.get(fileName).resolve(objectType).resolve(configurationPid + ".cfg");
+
+ File f = new File(path.toUri());
+/*
+ if ((this.configurationPid != null) && (this.bundleContext != null)) {
+
+ ServiceReference collectorRef =
+ this.bundleContext.getServiceReference(CustomConfigLocationCollector.class);
+ if (collectorRef != null) {
+ CustomConfigLocationCollector collector = this.bundleContext.getService(collectorRef);
+ if (collector != null)
+ collector.addCustomLocation(configurationPid, "file:/" + f.getAbsolutePath().replace("\\", "/"));
+ else
+ log.error("registerImmutables :: COLLECTOR IS NULL");
+ this.bundleContext.ungetService(collectorRef);
+ } else {
+ log.error("registerImmutables :: REF IS NULL");
+ }
+ }
+*/
+
+ if (!f.exists()) {
+ f.getParentFile().mkdirs();
+ f.createNewFile();
+ } else {
+ // we're not updating existing files
+ return;
+ }
+
+ ServiceReference refCR = bundleContext.getServiceReference(ConfigRepository.class);
+ if (refCR == null)
+ return;
+ ConfigRepository repo = bundleContext.getService(refCR);
+
+ TypedProperties typedProperties;
+
+/* ServiceReference refCA = bundleContext.getServiceReference(ConfigurationAdmin.class);
+ if (refCA == null)
+ return;
+ ConfigurationAdmin configAdmin = bundleContext.getService(refCA);
+ Configuration config = configAdmin.getConfiguration(configurationPid);
+ Dictionary props = config.getProperties();
+ Iterator iter = props.keys().asIterator();
+ System.out.println("PROPS :: ");
+ while(iter.hasNext()) {
+ String key = iter.next();
+ System.out.println(key + "-->" + props.get(key) + ":" + props.get(key).getClass().getName());
+ }
+
+ props.put("felix.fileinstall.filename", "file:/" + f.getAbsolutePath().replace("\\", "/"));
+ config.update(props);
+
+ TypedProperties typedProperties = repo.getConfig(configurationPid);
+
+ System.out.println("TYPED PROPS 0:: ");
+ for (Entry entry: typedProperties.entrySet())
+ System.out.println(entry.getKey() + "-->" + entry.getValue() + ":" + entry.getValue().getClass().getName());
+*/
+ typedProperties = repo.getConfig(configurationPid);
+
+
+ typedProperties.putAll(properties);
+ typedProperties.remove( Constants.SERVICE_PID );
+ typedProperties.remove( ConfigurationAdmin.SERVICE_FACTORYPID );
+ typedProperties.remove( "felix.fileinstall.filename" );
+
+ typedProperties.save(f);
+
+// typedProperties = repo.getConfig(configurationPid);
+// typedProperties.put("felix.fileinstall.filename", "file:/" + f.getAbsolutePath().replace("\\", "/"));
+
+/* repo.update(configurationPid, typedProperties);
+
+ typedProperties = repo.getConfig(configurationPid);
+
+ System.out.println("TYPED PROPS 2:: ");
+ for (Entry entry: typedProperties.entrySet())
+ System.out.println(entry.getKey() + "-->" + entry.getValue() + ":" + entry.getValue().getClass().getName());
+*/
+ bundleContext.ungetService(refCR);
+
+ } catch (IOException | InvalidSyntaxException e) {
+ log.error("Error registering default properties for " + configurationPid + "\n", e);
+ }
+
+ }
+
+ @Override
+ public int size() {
+ return properties.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return properties.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return properties.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return properties.containsValue(value);
+ }
+
+ @Override
+ public Object get(Object key) {
+ return properties.get(key);
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ return properties.put(key, value);
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return properties.remove(key);
+ }
+
+ @Override
+ public void putAll(Map extends String, ? extends Object> m) {
+ properties.putAll(m);
+ }
+
+ @Override
+ public void clear() {
+ properties.clear();
+ }
+
+ @Override
+ public Set keySet() {
+ return properties.keySet();
+ }
+
+ @Override
+ public Collection values() {
+ return properties.values();
+ }
+
+ @Override
+ public Set> entrySet() {
+ return properties.entrySet();
+ }
+
+}
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/DefaultPropertiesProviderWithImmutables.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/DefaultPropertiesProviderWithImmutables.java
new file mode 100644
index 00000000..32487951
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/DefaultPropertiesProviderWithImmutables.java
@@ -0,0 +1,97 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * configuration-test-1
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultPropertiesProviderWithImmutables extends DefaultPropertiesProvider implements Immutables {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultPropertiesProviderWithImmutables.class);
+
+ protected Map immutables;
+
+ public DefaultPropertiesProviderWithImmutables(String objectId
+ , String objectType
+ , String configurationPid
+ , BundleContext bundleContext
+ , Map configurables) {
+ super(objectId, objectType, configurationPid, bundleContext, configurables);
+ }
+
+ public DefaultPropertiesProviderWithImmutables(String configurationPid
+ , BundleContext bundleContext
+ , Map configurables) {
+ super(configurationPid, bundleContext, configurables);
+ }
+
+ public DefaultPropertiesProviderWithImmutables(String configurationPid
+ , BundleContext bundleContext
+ , Map configurables
+ , Map immutables) {
+ super(configurationPid, bundleContext, configurables);
+ this.immutables = immutables;
+ registerImmutables();
+ }
+
+ public DefaultPropertiesProviderWithImmutables(String objectId
+ , String objectType
+ , String configurationPid
+ , BundleContext bundleContext
+ , Map configurables
+ , Map immutables) {
+ super(objectId, objectType, configurationPid, bundleContext, configurables);
+ this.immutables = immutables;
+ registerImmutables();
+ }
+
+ protected void registerImmutables() {
+ if ((this.configurationPid != null) && (this.bundleContext != null)) {
+
+ ServiceReference collectorRef = this.bundleContext.getServiceReference(ImmutablesCollector.class);
+ if (collectorRef != null) {
+ ImmutablesCollector collector = this.bundleContext.getService(collectorRef);
+ if (collector != null)
+ collector.add(this);
+ else
+ log.error("registerImmutables :: COLLECTOR IS NULL");
+ this.bundleContext.ungetService(collectorRef);
+ } else {
+ log.error("registerImmutables :: REF IS NULL");
+ }
+ }
+
+ }
+
+ @Override
+ public String getPid() {
+ return this.configurationPid;
+ }
+
+ @Override
+ public Map getProperties() {
+ return this.immutables;
+ };
+
+}
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/Immutables.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/Immutables.java
new file mode 100644
index 00000000..9c5b2789
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/Immutables.java
@@ -0,0 +1,29 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * configuration-test-1
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+import java.util.Map;
+
+public interface Immutables {
+
+ String getPid();
+ Map getProperties();
+
+}
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesCollector.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesCollector.java
new file mode 100644
index 00000000..d8640231
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesCollector.java
@@ -0,0 +1,26 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * configuration-test-1
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+public interface ImmutablesCollector {
+
+ void add(Immutables immutables);
+
+}
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesConfigurationPlugin.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesConfigurationPlugin.java
new file mode 100644
index 00000000..8c2e58ff
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesConfigurationPlugin.java
@@ -0,0 +1,117 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * configuration-test-1
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationPlugin;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service = {ConfigurationPlugin.class, ImmutablesCollector.class}, immediate = true,
+ property = {ConfigurationPlugin.CM_TARGET + "=*"
+ , ConfigurationPlugin.CM_RANKING + "=100"
+ , "config.plugin.id=ImmutablesConfigurationPlugin"})
+public class ImmutablesConfigurationPlugin implements ConfigurationPlugin, ImmutablesCollector {
+
+ private static final Logger log = LoggerFactory.getLogger(ImmutablesConfigurationPlugin.class);
+
+ protected BundleContext bundleContext;
+
+ protected Map immutablesMap = new HashMap<>();
+
+ protected Map> immutablesDataMap = new HashMap<>();
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ ConfigurationAdmin configurationAdmin;
+
+ public void activate(ComponentContext componentContext) {
+ this.bundleContext = componentContext.getBundleContext();
+ log.debug("ImmutablesConfigurationPlugin activated");
+ }
+
+ @Override
+ public void modifyConfiguration(ServiceReference> reference, Dictionary properties) {
+ String pid = properties.get(Constants.SERVICE_PID).toString();
+ if (immutablesDataMap.containsKey(pid)) {
+ Dictionary ims = immutablesDataMap.get(pid);
+ Iterator iter = ims.keys().asIterator();
+ while (iter.hasNext()) {
+ String key = iter.next();
+ properties.put(key, ims.get(key));
+ }
+ log.debug("DATA: " + pid + " FOUND");
+ } else {
+ log.debug("DATA: " + pid + " NOT FOUND");
+ }
+ }
+
+ @Override
+ public void add(Immutables immutables) {
+ synchronized (immutablesDataMap) {
+ boolean reload = true;
+ if (immutablesDataMap.containsKey(immutables.getPid())) {
+ Dictionary current = immutablesDataMap.get(immutables.getPid());
+ reload = !immutables.getProperties().entrySet().stream()
+ .allMatch(e -> e.getValue().equals(current.get(e.getKey())));
+ }
+ if (!reload) {
+ log.debug("Immutables for " + immutables.getPid() + " already loaded");
+ return;
+ }
+ immutablesDataMap.remove(immutables.getPid());
+ log.debug("Adding direct Immutables for " + immutables.getPid());
+ Dictionary ims = new Hashtable<>();
+ Map properties = immutables.getProperties();
+ if (properties != null)
+ for (Entry entry: properties.entrySet())
+ ims.put(entry.getKey(), entry.getValue());
+ immutablesDataMap.put(immutables.getPid(), ims);
+ try {
+ Dictionary props = configurationAdmin.getConfiguration(immutables.getPid()).getProperties();
+ if (props == null)
+ props = new Hashtable<>();
+ Iterator keys = ims.keys().asIterator();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ props.put(key, ims.get(key));
+ }
+ configurationAdmin.getConfiguration(immutables.getPid()).setBundleLocation("?");
+ configurationAdmin.getConfiguration(immutables.getPid()).update(props);
+ } catch (IOException e) {
+ log.error("Failed updateing configuration", e);
+ }
+ }
+ }
+}
diff --git a/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesImpl.java b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesImpl.java
new file mode 100644
index 00000000..2da78f44
--- /dev/null
+++ b/platform/runtime/base/config-extensions/src/main/java/ru/entaxy/platform/base/config/ImmutablesImpl.java
@@ -0,0 +1,99 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * configuration-test-1
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.config;
+
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ImmutablesImpl implements Immutables {
+
+ private static final Logger log = LoggerFactory.getLogger(ImmutablesImpl.class);
+
+ protected BundleContext bundleContext;
+
+ protected String pid;
+ protected Map properties;
+
+ public ImmutablesImpl() {
+ super();
+ }
+
+ public ImmutablesImpl(String pid, BundleContext bundleContext) {
+ super();
+ setPid(pid);
+ setBundleContext(bundleContext);
+ }
+
+ public ImmutablesImpl(String pid, BundleContext bundleContext, Map properties) {
+ super();
+ setProperties(properties);
+ setPid(pid);
+ setBundleContext(bundleContext);
+ }
+
+ public void setPid(String pid) {
+ this.pid = pid;
+ checkAndRegister();
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ checkAndRegister();
+ }
+
+ protected void checkAndRegister() {
+ if ((this.pid != null) && (this.bundleContext != null)) {
+
+ log.debug("\n\tcheckAndRegister :: START");
+
+ ServiceReference collectorRef = this.bundleContext.getServiceReference(ImmutablesCollector.class);
+ if (collectorRef != null) {
+ log.debug("\n\tcheckAndRegister :: GET COLLECTOR");
+ ImmutablesCollector collector = this.bundleContext.getService(collectorRef);
+ if (collector != null)
+ collector.add(this);
+ else
+ log.debug("\n\tcheckAndRegister :: COLLECTOR IS NULL");
+ this.bundleContext.ungetService(collectorRef);
+ } else {
+ log.debug("\n\tcheckAndRegister :: REF IS NULL");
+ }
+ }
+ }
+
+ @Override
+ public String getPid() {
+ return this.pid;
+ }
+
+ @Override
+ public Map getProperties() {
+ return this.properties;
+ }
+
+}
diff --git a/platform/runtime/base/connecting/adapter/adapters-core/pom.xml b/platform/runtime/base/connecting/adapter/adapters-core/pom.xml
index e1b980bc..0d7cb55e 100644
--- a/platform/runtime/base/connecting/adapter/adapters-core/pom.xml
+++ b/platform/runtime/base/connecting/adapter/adapters-core/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBean.java b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBean.java
index 81c75983..98307329 100644
--- a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBean.java
+++ b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBean.java
@@ -19,7 +19,9 @@
*/
package ru.entaxy.esb.platform.runtime.base.connecting.adapter.core.management;
-public interface AdapterMBean {
+import ru.entaxy.esb.platform.base.management.core.api.RuntimeTypedMBean;
+
+public interface AdapterMBean extends RuntimeTypedMBean {
public boolean isInited();
diff --git a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBeanImpl.java b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBeanImpl.java
index cd9f7e11..70befc0a 100644
--- a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBeanImpl.java
+++ b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdapterMBeanImpl.java
@@ -22,8 +22,11 @@ package ru.entaxy.esb.platform.runtime.base.connecting.adapter.core.management;
import javax.management.NotCompliantMBeanException;
import javax.management.StandardMBean;
+import ru.entaxy.esb.platform.base.management.core.api.EntaxyRuntimeTyped;
import ru.entaxy.esb.platform.runtime.base.connecting.adapter.core.api.Adapter;
+//@TODO move string to constant
+@EntaxyRuntimeTyped(name = "entaxy.runtime.adapter")
public class AdapterMBeanImpl extends StandardMBean implements AdapterMBean {
protected Adapter adapter;
diff --git a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBean.java b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBean.java
index 9781d762..f3ab7254 100644
--- a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBean.java
+++ b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBean.java
@@ -24,9 +24,9 @@ import ru.entaxy.esb.platform.base.management.core.Qualifier;
public interface AdaptersMBean {
- public static final String ADAPTERS_KEY = "categrory";
+ public static final String ADAPTERS_KEY = "category";
- public static final String ADAPTERS_VALUE = "adapters";
+ public static final String ADAPTERS_VALUE = "adapter";
public static final Qualifier Q_ADAPTERS = ManagementCore.Q_PLATFORM.qualifier(ADAPTERS_KEY, ADAPTERS_VALUE);
diff --git a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBeanImpl.java b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBeanImpl.java
index 048d1d7f..f286f69b 100644
--- a/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBeanImpl.java
+++ b/platform/runtime/base/connecting/adapter/adapters-core/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/adapter/core/management/AdaptersMBeanImpl.java
@@ -67,7 +67,7 @@ public class AdaptersMBeanImpl extends StandardMBean implements AdaptersMBean {
@Activate
public void activate(ComponentContext componentContext) {
- log.info(" >> ACTIVATE <<");
+ log.debug(" >> ACTIVATE <<");
this.bundleContext = componentContext.getBundleContext();
}
diff --git a/platform/runtime/base/connecting/adapter/amqp-adapter/pom.xml b/platform/runtime/base/connecting/adapter/amqp-adapter/pom.xml
index eb36609f..3bf77de2 100644
--- a/platform/runtime/base/connecting/adapter/amqp-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/amqp-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index 95aedb54..229cffbb 100644
--- a/platform/runtime/base/connecting/adapter/amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -55,7 +55,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${destinationType}:${destinationName}"
+ "expression": "${destinationType}:${destinationName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/artemis-adapter/pom.xml b/platform/runtime/base/connecting/adapter/artemis-adapter/pom.xml
index 54dafacb..bed05854 100644
--- a/platform/runtime/base/connecting/adapter/artemis-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/artemis-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/artemis-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/artemis-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index c8eb663f..b6542fa6 100644
--- a/platform/runtime/base/connecting/adapter/artemis-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/artemis-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -665,7 +665,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${destinationType}:${destinationName}"
+ "expression": "${destinationType}:${destinationName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/pom.xml b/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/pom.xml
index 2a0c189e..7f984ee9 100644
--- a/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index d9966f6a..4d6a7677 100644
--- a/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/artemis-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -55,7 +55,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${destinationType}:${destinationName}"
+ "expression": "${destinationType}:${destinationName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/file-adapter/pom.xml b/platform/runtime/base/connecting/adapter/file-adapter/pom.xml
index 0cf8cd70..01c745cb 100644
--- a/platform/runtime/base/connecting/adapter/file-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/file-adapter/pom.xml
@@ -1,11 +1,10 @@
-
+
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
@@ -19,6 +18,9 @@
*
+ ru.entaxy.platform.adapter.file
+ template,
+ ru.entaxy.adapter
@@ -30,11 +32,30 @@
true
- true
-
+
+ true
+ true
-
\ No newline at end of file
+
+
+ org.apache.camel
+ camel-file
+ ${camel.version}
+
+
+ org.apache.camel
+ camel-util
+ ${camel.version}
+
+
+ ru.entaxy.esb.platform.runtime.base
+ base-support
+ ${project.version}
+
+
+
diff --git a/platform/runtime/base/connecting/adapter/file-adapter/src/main/java/ru/entaxy/platform/adapter/file/ExtendedFileComponent.java b/platform/runtime/base/connecting/adapter/file-adapter/src/main/java/ru/entaxy/platform/adapter/file/ExtendedFileComponent.java
new file mode 100644
index 00000000..d571e024
--- /dev/null
+++ b/platform/runtime/base/connecting/adapter/file-adapter/src/main/java/ru/entaxy/platform/adapter/file/ExtendedFileComponent.java
@@ -0,0 +1,69 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * file-adapter
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.adapter.file;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.camel.component.file.FileComponent;
+import org.apache.camel.component.file.GenericFileEndpoint;
+import org.apache.camel.util.StringHelper;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+
+public class ExtendedFileComponent extends FileComponent {
+
+ protected String rootDirectory = "";
+
+ @Override
+ protected GenericFileEndpoint buildFileEndpoint(String uri, String remaining, Map parameters)
+ throws Exception {
+
+ // copied from parent
+ if (StringHelper.hasStartToken(remaining, "simple")) {
+ throw new IllegalArgumentException("Invalid directory: " + remaining + ". Dynamic expressions with ${ } placeholders is not allowed."
+ + " Use the fileName option to set the dynamic expression.");
+ }
+
+ String current = remaining;
+ if (CommonUtils.isValid(rootDirectory)) {
+ current = rootDirectory;
+ if (CommonUtils.isValid(remaining) && !".".equals(remaining)) {
+ if (!current.endsWith("/"))
+ current += "/";
+ if (remaining.startsWith("/"))
+ current += remaining.substring(1);
+ else
+ current += remaining;
+ }
+ }
+ log.debug("CREATING ENDPOINT FOR [{}]", current);
+ return super.buildFileEndpoint(uri, current, parameters);
+ }
+
+ public String getRootDirectory() {
+ return rootDirectory;
+ }
+
+ public void setRootDirectory(String rootDirectory) {
+ this.rootDirectory = rootDirectory;
+ }
+
+}
diff --git a/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index f145fa4f..42a21026 100644
--- a/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -516,7 +516,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${directoryName}"
+ "expression": "${directoryName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/factory/file-adapter.json b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/factory/file-adapter.json
new file mode 100644
index 00000000..9b653178
--- /dev/null
+++ b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/factory/file-adapter.json
@@ -0,0 +1,2746 @@
+{
+ "factory": {
+ "id": "file-adapter",
+ "type": "entaxy.runtime.connection",
+ "label": "file,core",
+ "description": "Read and write files.",
+ "category": "adapter"
+ },
+ "entaxy.runtime.connection": {},
+ "fields": {
+ "bridgeErrorHandler": {
+ "displayName": "Bridge Error Handler",
+ "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored.",
+ "label": "consumer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer",
+ "##others": {
+ "old": {
+ "kind": "property",
+ "javaType": "boolean",
+ "deprecated": false
+ },
+ "new": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ }
+ },
+ "lazyStartProducer": {
+ "displayName": "Lazy Start Producer",
+ "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel\u0027s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing.",
+ "label": "producer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "producer",
+ "##others": {
+ "old": {
+ "kind": "property",
+ "javaType": "boolean",
+ "deprecated": false
+ },
+ "new": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ }
+ },
+ "basicPropertyBinding": {
+ "displayName": "Basic Property Binding",
+ "description": "Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities",
+ "label": "advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "advanced",
+ "##others": {
+ "old": {
+ "kind": "property",
+ "javaType": "boolean",
+ "deprecated": false
+ },
+ "new": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ }
+ },
+ "directoryName": {
+ "displayName": "Directory Name",
+ "description": "The starting directory",
+ "label": "",
+ "type": "string",
+ "required": true,
+ "hidden": false,
+ "group": "common",
+ "##others": {
+ "kind": "path",
+ "javaType": "java.io.File",
+ "deprecated": false,
+ "deprecationNote": ""
+ }
+ },
+ "charset": {
+ "displayName": "Charset",
+ "description": "This option is used to specify the encoding of the file. You can use this on the consumer, to specify the encodings of the files, which allow Camel to know the charset it should load the file content in case the file content is being accessed. Likewise when writing a file, you can use this option to specify which charset to write the file as well. Do mind that when writing the file Camel may have to read the message content into memory to be able to convert the data into the configured charset, so do not use this if you have big messages.",
+ "label": "",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "common",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "doneFileName": {
+ "displayName": "Done File Name",
+ "description": "Producer: If provided, then Camel will write a 2nd done file when the original file has been written. The done file will be empty. This option configures what file name to use. Either you can specify a fixed name. Or you can use dynamic placeholders. The done file will always be written in the same folder as the original file. Consumer: If provided, Camel will only consume files if a done file exists. This option configures what file name to use. Either you can specify a fixed name. Or you can use dynamic placeholders.The done file is always expected in the same folder as the original file. Only ${file.name} and ${file.name.next} is supported as dynamic placeholders.",
+ "label": "",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "common",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "fileName": {
+ "displayName": "File Name",
+ "description": "Use Expression such as File Language to dynamically set the filename. For consumers, it\u0027s used as a filename filter. For producers, it\u0027s used to evaluate the filename to write. If an expression is set, it take precedence over the CamelFileName header. (Note: The header itself can also be an Expression). The expression options support both String and Expression types. If the expression is a String type, it is always evaluated using the File Language. If the expression is an Expression type, the specified Expression type is used - this allows you, for instance, to use OGNL expressions. For the consumer, you can use it to filter filenames, so you can for instance consume today\u0027s file using the File Language syntax: mydata-${date:now:yyyyMMdd}.txt. The producers support the CamelOverruleFileName header which takes precedence over any existing CamelFileName header; the CamelOverruleFileName is a header that is used only once, and makes it easier as this avoids to temporary store CamelFileName and have to restore it afterwards.",
+ "label": "",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "common",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "delete": {
+ "displayName": "Delete",
+ "description": "If true, the file will be deleted after it is processed successfully.",
+ "label": "consumer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "moveFailed": {
+ "displayName": "Move Failed",
+ "description": "Sets the move failure expression based on Simple language. For example, to move files into a .error subdirectory use: .error. Note: When moving the files to the fail location Camel will handle the error and will not pick up the file again.",
+ "label": "consumer",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "noop": {
+ "displayName": "Noop",
+ "description": "If true, the file is not moved or deleted in any way. This option is good for readonly data, or for ETL type requirements. If noop\u003dtrue, Camel will set idempotent\u003dtrue as well, to avoid consuming the same files over and over again.",
+ "label": "consumer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "preMove": {
+ "displayName": "Pre Move",
+ "description": "Expression (such as File Language) used to dynamically set the filename when moving it before processing. For example to move in-progress files into the order directory set this value to order.",
+ "label": "consumer",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "preSort": {
+ "displayName": "Pre Sort",
+ "description": "When pre-sort is enabled then the consumer will sort the file and directory names during polling, that was retrieved from the file system. You may want to do this in case you need to operate on the files in a sorted order. The pre-sort is executed before the consumer starts to filter, and accept files to process by Camel. This option is default\u003dfalse meaning disabled.",
+ "label": "consumer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "recursive": {
+ "displayName": "Recursive",
+ "description": "If a directory, will look for files in all the sub-directories as well.",
+ "label": "consumer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "sendEmptyMessageWhenIdle": {
+ "displayName": "Send Empty Message When Idle",
+ "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead.",
+ "label": "consumer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "directoryMustExist": {
+ "displayName": "Directory Must Exist",
+ "description": "Similar to the startingDirectoryMustExist option but this applies during polling (after starting the consumer).",
+ "label": "consumer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "exceptionHandler": {
+ "displayName": "Exception Handler",
+ "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored.",
+ "label": "consumer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.spi.ExceptionHandler",
+ "optionalPrefix": "consumer.",
+ "deprecated": false
+ }
+ },
+ "exchangePattern": {
+ "displayName": "Exchange Pattern",
+ "description": "Sets the exchange pattern when the consumer creates an exchange.",
+ "label": "consumer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.ExchangePattern",
+ "enum": [
+ "InOnly",
+ "InOut",
+ "InOptionalOut"
+ ],
+ "deprecated": false
+ }
+ },
+ "extendedAttributes": {
+ "displayName": "Extended Attributes",
+ "description": "To define which file attributes of interest. Like posix:permissions,posix:owner,basic:lastAccessTime, it supports basic wildcard like posix:, basic:lastAccessTime",
+ "label": "consumer,advanced",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "inProgressRepository": {
+ "displayName": "In Progress Repository",
+ "description": "A pluggable in-progress repository org.apache.camel.spi.IdempotentRepository. The in-progress repository is used to account the current in progress files being consumed. By default a memory based repository is used.",
+ "label": "consumer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.spi.IdempotentRepository",
+ "deprecated": false
+ }
+ },
+ "localWorkDirectory": {
+ "displayName": "Local Work Directory",
+ "description": "When consuming, a local work directory can be used to store the remote file content directly in local files, to avoid loading the content into memory. This is beneficial, if you consume a very big remote file and thus can conserve memory.",
+ "label": "consumer,advanced",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "onCompletionExceptionHandler": {
+ "displayName": "On Completion Exception Handler",
+ "description": "To use a custom org.apache.camel.spi.ExceptionHandler to handle any thrown exceptions that happens during the file on completion process where the consumer does either a commit or rollback. The default implementation will log any exception at WARN level and ignore.",
+ "label": "consumer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.spi.ExceptionHandler",
+ "deprecated": false
+ }
+ },
+ "pollStrategy": {
+ "displayName": "Poll Strategy",
+ "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel.",
+ "label": "consumer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy",
+ "deprecated": false
+ }
+ },
+ "probeContentType": {
+ "displayName": "Probe Content Type",
+ "description": "Whether to enable probing of the content type. If enable then the consumer uses Files#probeContentType(java.nio.file.Path) to determine the content-type of the file, and store that as a header with key Exchange#FILE_CONTENT_TYPE on the Message.",
+ "label": "consumer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "processStrategy": {
+ "displayName": "Process Strategy",
+ "description": "A pluggable org.apache.camel.component.file.GenericFileProcessStrategy allowing you to implement your own readLock option or similar. Can also be used when special conditions must be met before a file can be consumed, such as a special ready file exists. If this option is set then the readLock option does not apply.",
+ "label": "consumer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.component.file.GenericFileProcessStrategy\u003cjava.io.File\u003e",
+ "deprecated": false
+ }
+ },
+ "startingDirectoryMustExist": {
+ "displayName": "Starting Directory Must Exist",
+ "description": "Whether the starting directory must exist. Mind that the autoCreate option is default enabled, which means the starting directory is normally auto created if it doesn\u0027t exist. You can disable autoCreate and enable this to ensure the starting directory must exist. Will thrown an exception if the directory doesn\u0027t exist.",
+ "label": "consumer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "startingDirectoryMustHaveAccess": {
+ "displayName": "Starting Directory Must Have Access",
+ "description": "Whether the starting directory has access permissions. Mind that the startingDirectoryMustExist parameter must be set to true in order to verify that the directory exists. Will thrown an exception if the directory doesn\u0027t have read and write permissions.",
+ "label": "consumer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "consumer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "appendChars": {
+ "displayName": "Append Chars",
+ "description": "Used to append characters (text) after writing files. This can for example be used to add new lines or other separators when writing and appending to existing files. To specify new-line (slash-n or slash-r) or tab (slash-t) characters then escape with an extra slash, eg slash-slash-n.",
+ "label": "producer",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "fileExist": {
+ "displayName": "File Exist",
+ "description": "What to do if a file already exists with the same name. Override, which is the default, replaces the existing file. - Append - adds content to the existing file. - Fail - throws a GenericFileOperationException, indicating that there is already an existing file. - Ignore - silently ignores the problem and does not override the existing file, but assumes everything is okay. - Move - option requires to use the moveExisting option to be configured as well. The option eagerDeleteTargetFile can be used to control what to do if an moving the file, and there exists already an existing file, otherwise causing the move operation to fail. The Move option will move any existing files, before writing the target file. - TryRename is only applicable if tempFileName option is in use. This allows to try renaming the file from the temporary name to the actual name, without doing any exists check. This check may be faster on some file systems and especially FTP servers.",
+ "label": "producer",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "Override",
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.component.file.GenericFileExist",
+ "enum": [
+ "Override",
+ "Append",
+ "Fail",
+ "Ignore",
+ "Move",
+ "TryRename"
+ ],
+ "deprecated": false
+ }
+ },
+ "flatten": {
+ "displayName": "Flatten",
+ "description": "Flatten is used to flatten the file name path to strip any leading paths, so it\u0027s just the file name. This allows you to consume recursively into sub-directories, but when you eg write the files to another directory they will be written in a single directory. Setting this to true on the producer enforces that any file name in CamelFileName header will be stripped for any leading paths.",
+ "label": "producer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "jailStartingDirectory": {
+ "displayName": "Jail Starting Directory",
+ "description": "Used for jailing (restricting) writing files to the starting directory (and sub) only. This is enabled by default to not allow Camel to write files to outside directories (to be more secured out of the box). You can turn this off to allow writing files to directories outside the starting directory, such as parent or root folders.",
+ "label": "producer",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "moveExisting": {
+ "displayName": "Move Existing",
+ "description": "Expression (such as File Language) used to compute file name to use when fileExist\u003dMove is configured. To move files into a backup subdirectory just enter backup. This option only supports the following File Language tokens: file:name, file:name.ext, file:name.noext, file:onlyname, file:onlyname.noext, file:ext, and file:parent. Notice the file:parent is not supported by the FTP component, as the FTP component can only move any existing files to a relative directory based on current dir as base.",
+ "label": "producer",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "tempFileName": {
+ "displayName": "Temp File Name",
+ "description": "The same as tempPrefix option but offering a more fine grained control on the naming of the temporary filename as it uses the File Language. The location for tempFilename is relative to the final file location in the option \u0027fileName\u0027, not the target directory in the base uri. For example if option fileName includes a directory prefix: dir/finalFilename then tempFileName is relative to that subdirectory dir.",
+ "label": "producer",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "tempPrefix": {
+ "displayName": "Temp Prefix",
+ "description": "This option is used to write the file using a temporary name and then, after the write is complete, rename it to the real name. Can be used to identify files being written and also avoid consumers (not using exclusive read locks) reading in progress files. Is often used by FTP when uploading big files.",
+ "label": "producer",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "producer",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "allowNullBody": {
+ "displayName": "Allow Null Body",
+ "description": "Used to specify if a null body is allowed during file writing. If set to true then an empty file will be created, when set to false, and attempting to send a null body to the file component, a GenericFileWriteException of \u0027Cannot write null body to file.\u0027 will be thrown. If the fileExist option is set to \u0027Override\u0027, then the file will be truncated, and if set to append the file will remain unchanged.",
+ "label": "producer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "chmod": {
+ "displayName": "Chmod",
+ "description": "Specify the file permissions which is sent by the producer, the chmod value must be between 000 and 777; If there is a leading digit like in 0755 we will ignore it.",
+ "label": "producer,advanced",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "chmodDirectory": {
+ "displayName": "Chmod Directory",
+ "description": "Specify the directory permissions used when the producer creates missing directories, the chmod value must be between 000 and 777; If there is a leading digit like in 0755 we will ignore it.",
+ "label": "producer,advanced",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "eagerDeleteTargetFile": {
+ "displayName": "Eager Delete Target File",
+ "description": "Whether or not to eagerly delete any existing target file. This option only applies when you use fileExists\u003dOverride and the tempFileName option as well. You can use this to disable (set it to false) deleting the target file before the temp file is written. For example you may write big files and want the target file to exists during the temp file is being written. This ensure the target file is only deleted until the very last moment, just before the temp file is being renamed to the target filename. This option is also used to control whether to delete any existing files when fileExist\u003dMove is enabled, and an existing file exists. If this option copyAndDeleteOnRenameFails false, then an exception will be thrown if an existing file existed, if its true, then the existing file is deleted before the move operation.",
+ "label": "producer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "forceWrites": {
+ "displayName": "Force Writes",
+ "description": "Whether to force syncing writes to the file system. You can turn this off if you do not want this level of guarantee, for example if writing to logs / audit logs etc; this would yield better performance.",
+ "label": "producer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "keepLastModified": {
+ "displayName": "Keep Last Modified",
+ "description": "Will keep the last modified timestamp from the source file (if any). Will use the Exchange.FILE_LAST_MODIFIED header to located the timestamp. This header can contain either a java.util.Date or long with the timestamp. If the timestamp exists and the option is enabled it will set this timestamp on the written file. Note: This option only applies to the file producer. You cannot use this option with any of the ftp producers.",
+ "label": "producer,advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "moveExistingFileStrategy": {
+ "displayName": "Move Existing File Strategy",
+ "description": "Strategy (Custom Strategy) used to move file with special naming token to use when fileExist\u003dMove is configured. By default, there is an implementation used if no custom strategy is provided",
+ "label": "producer,advanced",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "producer (advanced)",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.component.file.strategy.FileMoveExistingStrategy",
+ "deprecated": false
+ }
+ },
+ "autoCreate": {
+ "displayName": "Auto Create",
+ "description": "Automatically create missing directories in the file\u0027s pathname. For the file consumer, that means creating the starting directory. For the file producer, it means the directory the files should be written to.",
+ "label": "advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "advanced",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "bufferSize": {
+ "displayName": "Buffer Size",
+ "description": "Buffer size in bytes used for writing files (or in case of FTP for downloading and uploading files).",
+ "label": "advanced",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "131072",
+ "group": "advanced",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "copyAndDeleteOnRenameFail": {
+ "displayName": "Copy And Delete On Rename Fail",
+ "description": "Whether to fallback and do a copy and delete file, in case the file could not be renamed directly. This option is not available for the FTP component.",
+ "label": "advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "advanced",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "renameUsingCopy": {
+ "displayName": "Rename Using Copy",
+ "description": "Perform rename operations using a copy and delete strategy. This is primarily used in environments where the regular rename operation is unreliable (e.g. across different file systems or networks). This option takes precedence over the copyAndDeleteOnRenameFail parameter that will automatically fall back to the copy and delete strategy, but only after additional delays.",
+ "label": "advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "advanced",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "synchronous": {
+ "displayName": "Synchronous",
+ "description": "Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported).",
+ "label": "advanced",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "false",
+ "group": "advanced",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "antExclude": {
+ "displayName": "Ant Exclude",
+ "description": "Ant style filter exclusion. If both antInclude and antExclude are used, antExclude takes precedence over antInclude. Multiple exclusions may be specified in comma-delimited format.",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "antFilterCaseSensitive": {
+ "displayName": "Ant Filter Case Sensitive",
+ "description": "Sets case sensitive flag on ant filter.",
+ "label": "consumer,filter",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "antInclude": {
+ "displayName": "Ant Include",
+ "description": "Ant style filter inclusion. Multiple inclusions may be specified in comma-delimited format.",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "eagerMaxMessagesPerPoll": {
+ "displayName": "Eager Max Messages Per Poll",
+ "description": "Allows for controlling whether the limit from maxMessagesPerPoll is eager or not. If eager then the limit is during the scanning of files. Where as false would scan all files, and then perform sorting. Setting this option to false allows for sorting all files first, and then limit the poll. Mind that this requires a higher memory usage as all file details are in memory to perform the sorting.",
+ "label": "consumer,filter",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "exclude": {
+ "displayName": "Exclude",
+ "description": "Is used to exclude files, if filename matches the regex pattern (matching is case in-senstive). Notice if you use symbols such as plus sign and others you would need to configure this using the RAW() syntax if configuring this as an endpoint uri. See more details at configuring endpoint uris",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "filter": {
+ "displayName": "Filter",
+ "description": "Pluggable filter as a org.apache.camel.component.file.GenericFileFilter class. Will skip files if filter returns false in its accept() method.",
+ "label": "consumer,filter",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.component.file.GenericFileFilter\u003cjava.io.File\u003e",
+ "deprecated": false
+ }
+ },
+ "filterDirectory": {
+ "displayName": "Filter Directory",
+ "description": "Filters the directory based on Simple language. For example to filter on current date, you can use a simple date pattern such as ${date:now:yyyMMdd}",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "filterFile": {
+ "displayName": "Filter File",
+ "description": "Filters the file based on Simple language. For example to filter on file size, you can use ${file:size} 5000",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "idempotent": {
+ "displayName": "Idempotent",
+ "description": "Option to use the Idempotent Consumer EIP pattern to let Camel skip already processed files. Will by default use a memory based LRUCache that holds 1000 entries. If noop\u003dtrue then idempotent will be enabled as well to avoid consuming the same files over and over again.",
+ "label": "consumer,filter",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "false",
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.Boolean",
+ "deprecated": false
+ }
+ },
+ "idempotentKey": {
+ "displayName": "Idempotent Key",
+ "description": "To use a custom idempotent key. By default the absolute path of the file is used. You can use the File Language, for example to use the file name and file size, you can do: idempotentKey\u003d${file:name}-${file:size}",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "idempotentRepository": {
+ "displayName": "Idempotent Repository",
+ "description": "A pluggable repository org.apache.camel.spi.IdempotentRepository which by default use MemoryMessageIdRepository if none is specified and idempotent is true.",
+ "label": "consumer,filter",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.spi.IdempotentRepository",
+ "deprecated": false
+ }
+ },
+ "include": {
+ "displayName": "Include",
+ "description": "Is used to include files, if filename matches the regex pattern (matching is case in-sensitive). Notice if you use symbols such as plus sign and others you would need to configure this using the RAW() syntax if configuring this as an endpoint uri. See more details at configuring endpoint uris",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "maxDepth": {
+ "displayName": "Max Depth",
+ "description": "The maximum depth to traverse when recursively processing a directory.",
+ "label": "consumer,filter",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "2147483647",
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "maxMessagesPerPoll": {
+ "displayName": "Max Messages Per Poll",
+ "description": "To define a maximum messages to gather per poll. By default no maximum is set. Can be used to set a limit of e.g. 1000 to avoid when starting up the server that there are thousands of files. Set a value of 0 or negative to disabled it. Notice: If this option is in use then the File and FTP components will limit before any sorting. For example if you have 100000 files and use maxMessagesPerPoll\u003d500, then only the first 500 files will be picked up, and then sorted. You can use the eagerMaxMessagesPerPoll option and set this to false to allow to scan all files first and then sort afterwards.",
+ "label": "consumer,filter",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "minDepth": {
+ "displayName": "Min Depth",
+ "description": "The minimum depth to start processing when recursively processing a directory. Using minDepth\u003d1 means the base directory. Using minDepth\u003d2 means the first sub directory.",
+ "label": "consumer,filter",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "move": {
+ "displayName": "Move",
+ "description": "Expression (such as Simple Language) used to dynamically set the filename when moving it after processing. To move files into a .done subdirectory just enter .done.",
+ "label": "consumer,filter",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "filter",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "exclusiveReadLockStrategy": {
+ "displayName": "Exclusive Read Lock Strategy",
+ "description": "Pluggable read-lock as a org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy implementation.",
+ "label": "consumer,lock",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy\u003cjava.io.File\u003e",
+ "deprecated": false
+ }
+ },
+ "readLock": {
+ "displayName": "Read Lock",
+ "description": "Used by consumer, to only poll the files if it has exclusive read-lock on the file (i.e. the file is not in-progress or being written). Camel will wait until the file lock is granted. This option provides the build in strategies: - none - No read lock is in use - markerFile - Camel creates a marker file (fileName.camelLock) and then holds a lock on it. This option is not available for the FTP component - changed - Changed is using file length/modification timestamp to detect whether the file is currently being copied or not. Will at least use 1 sec to determine this, so this option cannot consume files as fast as the others, but can be more reliable as the JDK IO API cannot always determine whether a file is currently being used by another process. The option readLockCheckInterval can be used to set the check frequency. - fileLock - is for using java.nio.channels.FileLock. This option is not avail for Windows OS and the FTP component. This approach should be avoided when accessing a remote file system via a mount/share unless that file system supports distributed file locks. - rename - rename is for using a try to rename the file as a test if we can get exclusive read-lock. - idempotent - (only for file component) idempotent is for using a idempotentRepository as the read-lock. This allows to use read locks that supports clustering if the idempotent repository implementation supports that. - idempotent-changed - (only for file component) idempotent-changed is for using a idempotentRepository and changed as the combined read-lock. This allows to use read locks that supports clustering if the idempotent repository implementation supports that. - idempotent-rename - (only for file component) idempotent-rename is for using a idempotentRepository and rename as the combined read-lock. This allows to use read locks that supports clustering if the idempotent repository implementation supports that.Notice: The various read locks is not all suited to work in clustered mode, where concurrent consumers on different nodes is competing for the same files on a shared file system. The markerFile using a close to atomic operation to create the empty marker file, but its not guaranteed to work in a cluster. The fileLock may work better but then the file system need to support distributed file locks, and so on. Using the idempotent read lock can support clustering if the idempotent repository supports clustering, such as Hazelcast Component or Infinispan.",
+ "label": "consumer,lock",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "none",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "enum": [
+ "none",
+ "markerFile",
+ "fileLock",
+ "rename",
+ "changed",
+ "idempotent",
+ "idempotent-changed",
+ "idempotent-rename"
+ ],
+ "deprecated": false
+ }
+ },
+ "readLockCheckInterval": {
+ "displayName": "Read Lock Check Interval",
+ "description": "Interval in millis for the read-lock, if supported by the read lock. This interval is used for sleeping between attempts to acquire the read lock. For example when using the changed read lock, you can set a higher interval period to cater for slow writes. The default of 1 sec. may be too fast if the producer is very slow writing the file. Notice: For FTP the default readLockCheckInterval is 5000. The readLockTimeout value must be higher than readLockCheckInterval, but a rule of thumb is to have a timeout that is at least 2 or more times higher than the readLockCheckInterval. This is needed to ensure that amble time is allowed for the read lock process to try to grab the lock before the timeout was hit.",
+ "label": "consumer,lock",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "1000",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "readLockDeleteOrphanLockFiles": {
+ "displayName": "Read Lock Delete Orphan Lock Files",
+ "description": "Whether or not read lock with marker files should upon startup delete any orphan read lock files, which may have been left on the file system, if Camel was not properly shutdown (such as a JVM crash). If turning this option to false then any orphaned lock file will cause Camel to not attempt to pickup that file, this could also be due another node is concurrently reading files from the same shared directory.",
+ "label": "consumer,lock",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "readLockIdempotentReleaseAsync": {
+ "displayName": "Read Lock Idempotent Release Async",
+ "description": "Whether the delayed release task should be synchronous or asynchronous. See more details at the readLockIdempotentReleaseDelay option.",
+ "label": "consumer,lock",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "readLockIdempotentReleaseAsyncPoolSize": {
+ "displayName": "Read Lock Idempotent Release Async Pool Size",
+ "description": "The number of threads in the scheduled thread pool when using asynchronous release tasks. Using a default of 1 core threads should be sufficient in almost all use-cases, only set this to a higher value if either updating the idempotent repository is slow, or there are a lot of files to process. This option is not in-use if you use a shared thread pool by configuring the readLockIdempotentReleaseExecutorService option. See more details at the readLockIdempotentReleaseDelay option.",
+ "label": "consumer,lock",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "readLockIdempotentReleaseDelay": {
+ "displayName": "Read Lock Idempotent Release Delay",
+ "description": "Whether to delay the release task for a period of millis. This can be used to delay the release tasks to expand the window when a file is regarded as read-locked, in an active/active cluster scenario with a shared idempotent repository, to ensure other nodes cannot potentially scan and acquire the same file, due to race-conditions. By expanding the time-window of the release tasks helps prevents these situations. Note delaying is only needed if you have configured readLockRemoveOnCommit to true.",
+ "label": "consumer,lock",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "readLockIdempotentReleaseExecutorService": {
+ "displayName": "Read Lock Idempotent Release Executor Service",
+ "description": "To use a custom and shared thread pool for asynchronous release tasks. See more details at the readLockIdempotentReleaseDelay option.",
+ "label": "consumer,lock",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.util.concurrent.ScheduledExecutorService",
+ "deprecated": false
+ }
+ },
+ "readLockLoggingLevel": {
+ "displayName": "Read Lock Logging Level",
+ "description": "Logging level used when a read lock could not be acquired. By default a DEBUG is logged. You can change this level, for example to OFF to not have any logging. This option is only applicable for readLock of types: changed, fileLock, idempotent, idempotent-changed, idempotent-rename, rename.",
+ "label": "consumer,lock",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "DEBUG",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.LoggingLevel",
+ "enum": [
+ "TRACE",
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "OFF"
+ ],
+ "deprecated": false
+ }
+ },
+ "readLockMarkerFile": {
+ "displayName": "Read Lock Marker File",
+ "description": "Whether to use marker file with the changed, rename, or exclusive read lock types. By default a marker file is used as well to guard against other processes picking up the same files. This behavior can be turned off by setting this option to false. For example if you do not want to write marker files to the file systems by the Camel application.",
+ "label": "consumer,lock",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "readLockMinAge": {
+ "displayName": "Read Lock Min Age",
+ "description": "This option is applied only for readLock\u003dchanged. It allows to specify a minimum age the file must be before attempting to acquire the read lock. For example use readLockMinAge\u003d300s to require the file is at last 5 minutes old. This can speedup the changed read lock as it will only attempt to acquire files which are at least that given age.",
+ "label": "consumer,lock",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "0",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "readLockMinLength": {
+ "displayName": "Read Lock Min Length",
+ "description": "This option is applied only for readLock\u003dchanged. It allows you to configure a minimum file length. By default Camel expects the file to contain data, and thus the default value is 1. You can set this option to zero, to allow consuming zero-length files.",
+ "label": "consumer,lock",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "1",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "readLockRemoveOnCommit": {
+ "displayName": "Read Lock Remove On Commit",
+ "description": "This option is applied only for readLock\u003didempotent. It allows to specify whether to remove the file name entry from the idempotent repository when processing the file is succeeded and a commit happens. By default the file is not removed which ensures that any race-condition do not occur so another active node may attempt to grab the file. Instead the idempotent repository may support eviction strategies that you can configure to evict the file name entry after X minutes - this ensures no problems with race conditions. See more details at the readLockIdempotentReleaseDelay option.",
+ "label": "consumer,lock",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "readLockRemoveOnRollback": {
+ "displayName": "Read Lock Remove On Rollback",
+ "description": "This option is applied only for readLock\u003didempotent. It allows to specify whether to remove the file name entry from the idempotent repository when processing the file failed and a rollback happens. If this option is false, then the file name entry is confirmed (as if the file did a commit).",
+ "label": "consumer,lock",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "readLockTimeout": {
+ "displayName": "Read Lock Timeout",
+ "description": "Optional timeout in millis for the read-lock, if supported by the read-lock. If the read-lock could not be granted and the timeout triggered, then Camel will skip the file. At next poll Camel, will try the file again, and this time maybe the read-lock could be granted. Use a value of 0 or lower to indicate forever. Currently fileLock, changed and rename support the timeout. Notice: For FTP the default readLockTimeout value is 20000 instead of 10000. The readLockTimeout value must be higher than readLockCheckInterval, but a rule of thumb is to have a timeout that is at least 2 or more times higher than the readLockCheckInterval. This is needed to ensure that amble time is allowed for the read lock process to try to grab the lock before the timeout was hit.",
+ "label": "consumer,lock",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "10000",
+ "group": "lock",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "backoffErrorThreshold": {
+ "displayName": "Backoff Error Threshold",
+ "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in.",
+ "label": "consumer,scheduler",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "backoffIdleThreshold": {
+ "displayName": "Backoff Idle Threshold",
+ "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in.",
+ "label": "consumer,scheduler",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "backoffMultiplier": {
+ "displayName": "Backoff Multiplier",
+ "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and/or backoffErrorThreshold must also be configured.",
+ "label": "consumer,scheduler",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "int",
+ "deprecated": false
+ }
+ },
+ "delay": {
+ "displayName": "Delay",
+ "description": "Milliseconds before the next poll.",
+ "label": "consumer,scheduler",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "500",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "greedy": {
+ "displayName": "Greedy",
+ "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages.",
+ "label": "consumer,scheduler",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "initialDelay": {
+ "displayName": "Initial Delay",
+ "description": "Milliseconds before the first poll starts.",
+ "label": "consumer,scheduler",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "1000",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "repeatCount": {
+ "displayName": "Repeat Count",
+ "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever.",
+ "label": "consumer,scheduler",
+ "type": "integer",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "0",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "long",
+ "deprecated": false
+ }
+ },
+ "runLoggingLevel": {
+ "displayName": "Run Logging Level",
+ "description": "The consumer logs a start/complete log line when it polls. This option allows you to configure the logging level for that.",
+ "label": "consumer,scheduler",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "TRACE",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "org.apache.camel.LoggingLevel",
+ "enum": [
+ "TRACE",
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "OFF"
+ ],
+ "deprecated": false
+ }
+ },
+ "scheduledExecutorService": {
+ "displayName": "Scheduled Executor Service",
+ "description": "Allows for configuring a custom/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool.",
+ "label": "consumer,scheduler",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.util.concurrent.ScheduledExecutorService",
+ "deprecated": false
+ }
+ },
+ "scheduler": {
+ "displayName": "Scheduler",
+ "description": "To use a cron scheduler from either camel-spring or camel-quartz component",
+ "label": "consumer,scheduler",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "none",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "enum": [
+ "none",
+ "spring",
+ "quartz"
+ ],
+ "deprecated": false
+ }
+ },
+ "schedulerProperties": {
+ "displayName": "Scheduler Properties",
+ "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler.",
+ "label": "consumer,scheduler",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.util.Map\u003cjava.lang.String, java.lang.Object\u003e",
+ "prefix": "scheduler.",
+ "multiValue": true,
+ "deprecated": false
+ }
+ },
+ "startScheduler": {
+ "displayName": "Start Scheduler",
+ "description": "Whether the scheduler should be auto started.",
+ "label": "consumer,scheduler",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "timeUnit": {
+ "displayName": "Time Unit",
+ "description": "Time unit for initialDelay and delay options.",
+ "label": "consumer,scheduler",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "MILLISECONDS",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.util.concurrent.TimeUnit",
+ "enum": [
+ "NANOSECONDS",
+ "MICROSECONDS",
+ "MILLISECONDS",
+ "SECONDS",
+ "MINUTES",
+ "HOURS",
+ "DAYS"
+ ],
+ "deprecated": false
+ }
+ },
+ "useFixedDelay": {
+ "displayName": "Use Fixed Delay",
+ "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details.",
+ "label": "consumer,scheduler",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": "true",
+ "group": "scheduler",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "shuffle": {
+ "displayName": "Shuffle",
+ "description": "To shuffle the list of files (sort in random order)",
+ "label": "consumer,sort",
+ "type": "boolean",
+ "required": false,
+ "hidden": false,
+ "defaultValue": false,
+ "group": "sort",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "boolean",
+ "deprecated": false
+ }
+ },
+ "sortBy": {
+ "displayName": "Sort By",
+ "description": "Built-in sort by using the File Language. Supports nested sorts, so you can have a sort by file name and as a 2nd group sort by modified date.",
+ "label": "consumer,sort",
+ "type": "string",
+ "required": false,
+ "hidden": false,
+ "group": "sort",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.lang.String",
+ "deprecated": false
+ }
+ },
+ "sorter": {
+ "displayName": "Sorter",
+ "description": "Pluggable sorter as a java.util.Comparator class.",
+ "label": "consumer,sort",
+ "type": "object",
+ "required": false,
+ "hidden": false,
+ "group": "sort",
+ "##others": {
+ "kind": "parameter",
+ "javaType": "java.util.Comparator\u003corg.apache.camel.component.file.GenericFile\u003cjava.io.File\u003e\u003e",
+ "deprecated": false
+ }
+ },
+ "rootDirectory": {
+ "type": "String",
+ "group": "entaxy",
+ "required": true
+ }
+ },
+ "outputs": {
+ "init": {
+ "isDefault": true,
+ "generator": "",
+ "config": {
+ "configurable": true
+ },
+ "fields": {
+ "rootDirectory": {}
+ }
+ }
+ },
+ "##origin": {
+ "component": {
+ "kind": "component",
+ "name": "file",
+ "title": "File",
+ "description": "Read and write files.",
+ "deprecated": false,
+ "firstVersion": "1.0.0",
+ "label": "file,core",
+ "javaType": "org.apache.camel.component.file.FileComponent",
+ "supportLevel": "Stable",
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-file",
+ "version": "3.4.5",
+ "scheme": "file",
+ "extendsScheme": "",
+ "syntax": "file:directoryName",
+ "async": false,
+ "consumerOnly": false,
+ "producerOnly": false,
+ "lenientProperties": false
+ },
+ "componentProperties": {
+ "bridgeErrorHandler": {
+ "kind": "property",
+ "displayName": "Bridge Error Handler",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored."
+ },
+ "lazyStartProducer": {
+ "kind": "property",
+ "displayName": "Lazy Start Producer",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel\u0027s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing."
+ },
+ "basicPropertyBinding": {
+ "kind": "property",
+ "displayName": "Basic Property Binding",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities"
+ }
+ },
+ "properties": {
+ "directoryName": {
+ "kind": "path",
+ "displayName": "Directory Name",
+ "group": "common",
+ "label": "",
+ "required": true,
+ "type": "string",
+ "javaType": "java.io.File",
+ "deprecated": false,
+ "deprecationNote": "",
+ "secret": false,
+ "description": "The starting directory"
+ },
+ "charset": {
+ "kind": "parameter",
+ "displayName": "Charset",
+ "group": "common",
+ "label": "",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "This option is used to specify the encoding of the file. You can use this on the consumer, to specify the encodings of the files, which allow Camel to know the charset it should load the file content in case the file content is being accessed. Likewise when writing a file, you can use this option to specify which charset to write the file as well. Do mind that when writing the file Camel may have to read the message content into memory to be able to convert the data into the configured charset, so do not use this if you have big messages."
+ },
+ "doneFileName": {
+ "kind": "parameter",
+ "displayName": "Done File Name",
+ "group": "common",
+ "label": "",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Producer: If provided, then Camel will write a 2nd done file when the original file has been written. The done file will be empty. This option configures what file name to use. Either you can specify a fixed name. Or you can use dynamic placeholders. The done file will always be written in the same folder as the original file. Consumer: If provided, Camel will only consume files if a done file exists. This option configures what file name to use. Either you can specify a fixed name. Or you can use dynamic placeholders.The done file is always expected in the same folder as the original file. Only ${file.name} and ${file.name.next} is supported as dynamic placeholders."
+ },
+ "fileName": {
+ "kind": "parameter",
+ "displayName": "File Name",
+ "group": "common",
+ "label": "",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Use Expression such as File Language to dynamically set the filename. For consumers, it\u0027s used as a filename filter. For producers, it\u0027s used to evaluate the filename to write. If an expression is set, it take precedence over the CamelFileName header. (Note: The header itself can also be an Expression). The expression options support both String and Expression types. If the expression is a String type, it is always evaluated using the File Language. If the expression is an Expression type, the specified Expression type is used - this allows you, for instance, to use OGNL expressions. For the consumer, you can use it to filter filenames, so you can for instance consume today\u0027s file using the File Language syntax: mydata-${date:now:yyyyMMdd}.txt. The producers support the CamelOverruleFileName header which takes precedence over any existing CamelFileName header; the CamelOverruleFileName is a header that is used only once, and makes it easier as this avoids to temporary store CamelFileName and have to restore it afterwards."
+ },
+ "bridgeErrorHandler": {
+ "kind": "parameter",
+ "displayName": "Bridge Error Handler",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored."
+ },
+ "delete": {
+ "kind": "parameter",
+ "displayName": "Delete",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "If true, the file will be deleted after it is processed successfully."
+ },
+ "moveFailed": {
+ "kind": "parameter",
+ "displayName": "Move Failed",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Sets the move failure expression based on Simple language. For example, to move files into a .error subdirectory use: .error. Note: When moving the files to the fail location Camel will handle the error and will not pick up the file again."
+ },
+ "noop": {
+ "kind": "parameter",
+ "displayName": "Noop",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "If true, the file is not moved or deleted in any way. This option is good for readonly data, or for ETL type requirements. If noop\u003dtrue, Camel will set idempotent\u003dtrue as well, to avoid consuming the same files over and over again."
+ },
+ "preMove": {
+ "kind": "parameter",
+ "displayName": "Pre Move",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Expression (such as File Language) used to dynamically set the filename when moving it before processing. For example to move in-progress files into the order directory set this value to order."
+ },
+ "preSort": {
+ "kind": "parameter",
+ "displayName": "Pre Sort",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "When pre-sort is enabled then the consumer will sort the file and directory names during polling, that was retrieved from the file system. You may want to do this in case you need to operate on the files in a sorted order. The pre-sort is executed before the consumer starts to filter, and accept files to process by Camel. This option is default\u003dfalse meaning disabled."
+ },
+ "recursive": {
+ "kind": "parameter",
+ "displayName": "Recursive",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "If a directory, will look for files in all the sub-directories as well."
+ },
+ "sendEmptyMessageWhenIdle": {
+ "kind": "parameter",
+ "displayName": "Send Empty Message When Idle",
+ "group": "consumer",
+ "label": "consumer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead."
+ },
+ "directoryMustExist": {
+ "kind": "parameter",
+ "displayName": "Directory Must Exist",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Similar to the startingDirectoryMustExist option but this applies during polling (after starting the consumer)."
+ },
+ "exceptionHandler": {
+ "kind": "parameter",
+ "displayName": "Exception Handler",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.spi.ExceptionHandler",
+ "optionalPrefix": "consumer.",
+ "deprecated": false,
+ "secret": false,
+ "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored."
+ },
+ "exchangePattern": {
+ "kind": "parameter",
+ "displayName": "Exchange Pattern",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.ExchangePattern",
+ "enum": [
+ "InOnly",
+ "InOut",
+ "InOptionalOut"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "description": "Sets the exchange pattern when the consumer creates an exchange."
+ },
+ "extendedAttributes": {
+ "kind": "parameter",
+ "displayName": "Extended Attributes",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "To define which file attributes of interest. Like posix:permissions,posix:owner,basic:lastAccessTime, it supports basic wildcard like posix:, basic:lastAccessTime"
+ },
+ "inProgressRepository": {
+ "kind": "parameter",
+ "displayName": "In Progress Repository",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.spi.IdempotentRepository",
+ "deprecated": false,
+ "secret": false,
+ "description": "A pluggable in-progress repository org.apache.camel.spi.IdempotentRepository. The in-progress repository is used to account the current in progress files being consumed. By default a memory based repository is used."
+ },
+ "localWorkDirectory": {
+ "kind": "parameter",
+ "displayName": "Local Work Directory",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "When consuming, a local work directory can be used to store the remote file content directly in local files, to avoid loading the content into memory. This is beneficial, if you consume a very big remote file and thus can conserve memory."
+ },
+ "onCompletionExceptionHandler": {
+ "kind": "parameter",
+ "displayName": "On Completion Exception Handler",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.spi.ExceptionHandler",
+ "deprecated": false,
+ "secret": false,
+ "description": "To use a custom org.apache.camel.spi.ExceptionHandler to handle any thrown exceptions that happens during the file on completion process where the consumer does either a commit or rollback. The default implementation will log any exception at WARN level and ignore."
+ },
+ "pollStrategy": {
+ "kind": "parameter",
+ "displayName": "Poll Strategy",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy",
+ "deprecated": false,
+ "secret": false,
+ "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel."
+ },
+ "probeContentType": {
+ "kind": "parameter",
+ "displayName": "Probe Content Type",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether to enable probing of the content type. If enable then the consumer uses Files#probeContentType(java.nio.file.Path) to determine the content-type of the file, and store that as a header with key Exchange#FILE_CONTENT_TYPE on the Message."
+ },
+ "processStrategy": {
+ "kind": "parameter",
+ "displayName": "Process Strategy",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.component.file.GenericFileProcessStrategy\u003cjava.io.File\u003e",
+ "deprecated": false,
+ "secret": false,
+ "description": "A pluggable org.apache.camel.component.file.GenericFileProcessStrategy allowing you to implement your own readLock option or similar. Can also be used when special conditions must be met before a file can be consumed, such as a special ready file exists. If this option is set then the readLock option does not apply."
+ },
+ "startingDirectoryMustExist": {
+ "kind": "parameter",
+ "displayName": "Starting Directory Must Exist",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the starting directory must exist. Mind that the autoCreate option is default enabled, which means the starting directory is normally auto created if it doesn\u0027t exist. You can disable autoCreate and enable this to ensure the starting directory must exist. Will thrown an exception if the directory doesn\u0027t exist."
+ },
+ "startingDirectoryMustHaveAccess": {
+ "kind": "parameter",
+ "displayName": "Starting Directory Must Have Access",
+ "group": "consumer (advanced)",
+ "label": "consumer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the starting directory has access permissions. Mind that the startingDirectoryMustExist parameter must be set to true in order to verify that the directory exists. Will thrown an exception if the directory doesn\u0027t have read and write permissions."
+ },
+ "appendChars": {
+ "kind": "parameter",
+ "displayName": "Append Chars",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Used to append characters (text) after writing files. This can for example be used to add new lines or other separators when writing and appending to existing files. To specify new-line (slash-n or slash-r) or tab (slash-t) characters then escape with an extra slash, eg slash-slash-n."
+ },
+ "fileExist": {
+ "kind": "parameter",
+ "displayName": "File Exist",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.component.file.GenericFileExist",
+ "enum": [
+ "Override",
+ "Append",
+ "Fail",
+ "Ignore",
+ "Move",
+ "TryRename"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "Override",
+ "description": "What to do if a file already exists with the same name. Override, which is the default, replaces the existing file. - Append - adds content to the existing file. - Fail - throws a GenericFileOperationException, indicating that there is already an existing file. - Ignore - silently ignores the problem and does not override the existing file, but assumes everything is okay. - Move - option requires to use the moveExisting option to be configured as well. The option eagerDeleteTargetFile can be used to control what to do if an moving the file, and there exists already an existing file, otherwise causing the move operation to fail. The Move option will move any existing files, before writing the target file. - TryRename is only applicable if tempFileName option is in use. This allows to try renaming the file from the temporary name to the actual name, without doing any exists check. This check may be faster on some file systems and especially FTP servers."
+ },
+ "flatten": {
+ "kind": "parameter",
+ "displayName": "Flatten",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Flatten is used to flatten the file name path to strip any leading paths, so it\u0027s just the file name. This allows you to consume recursively into sub-directories, but when you eg write the files to another directory they will be written in a single directory. Setting this to true on the producer enforces that any file name in CamelFileName header will be stripped for any leading paths."
+ },
+ "jailStartingDirectory": {
+ "kind": "parameter",
+ "displayName": "Jail Starting Directory",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Used for jailing (restricting) writing files to the starting directory (and sub) only. This is enabled by default to not allow Camel to write files to outside directories (to be more secured out of the box). You can turn this off to allow writing files to directories outside the starting directory, such as parent or root folders."
+ },
+ "lazyStartProducer": {
+ "kind": "parameter",
+ "displayName": "Lazy Start Producer",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel\u0027s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing."
+ },
+ "moveExisting": {
+ "kind": "parameter",
+ "displayName": "Move Existing",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Expression (such as File Language) used to compute file name to use when fileExist\u003dMove is configured. To move files into a backup subdirectory just enter backup. This option only supports the following File Language tokens: file:name, file:name.ext, file:name.noext, file:onlyname, file:onlyname.noext, file:ext, and file:parent. Notice the file:parent is not supported by the FTP component, as the FTP component can only move any existing files to a relative directory based on current dir as base."
+ },
+ "tempFileName": {
+ "kind": "parameter",
+ "displayName": "Temp File Name",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "The same as tempPrefix option but offering a more fine grained control on the naming of the temporary filename as it uses the File Language. The location for tempFilename is relative to the final file location in the option \u0027fileName\u0027, not the target directory in the base uri. For example if option fileName includes a directory prefix: dir/finalFilename then tempFileName is relative to that subdirectory dir."
+ },
+ "tempPrefix": {
+ "kind": "parameter",
+ "displayName": "Temp Prefix",
+ "group": "producer",
+ "label": "producer",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "This option is used to write the file using a temporary name and then, after the write is complete, rename it to the real name. Can be used to identify files being written and also avoid consumers (not using exclusive read locks) reading in progress files. Is often used by FTP when uploading big files."
+ },
+ "allowNullBody": {
+ "kind": "parameter",
+ "displayName": "Allow Null Body",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Used to specify if a null body is allowed during file writing. If set to true then an empty file will be created, when set to false, and attempting to send a null body to the file component, a GenericFileWriteException of \u0027Cannot write null body to file.\u0027 will be thrown. If the fileExist option is set to \u0027Override\u0027, then the file will be truncated, and if set to append the file will remain unchanged."
+ },
+ "chmod": {
+ "kind": "parameter",
+ "displayName": "Chmod",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Specify the file permissions which is sent by the producer, the chmod value must be between 000 and 777; If there is a leading digit like in 0755 we will ignore it."
+ },
+ "chmodDirectory": {
+ "kind": "parameter",
+ "displayName": "Chmod Directory",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Specify the directory permissions used when the producer creates missing directories, the chmod value must be between 000 and 777; If there is a leading digit like in 0755 we will ignore it."
+ },
+ "eagerDeleteTargetFile": {
+ "kind": "parameter",
+ "displayName": "Eager Delete Target File",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Whether or not to eagerly delete any existing target file. This option only applies when you use fileExists\u003dOverride and the tempFileName option as well. You can use this to disable (set it to false) deleting the target file before the temp file is written. For example you may write big files and want the target file to exists during the temp file is being written. This ensure the target file is only deleted until the very last moment, just before the temp file is being renamed to the target filename. This option is also used to control whether to delete any existing files when fileExist\u003dMove is enabled, and an existing file exists. If this option copyAndDeleteOnRenameFails false, then an exception will be thrown if an existing file existed, if its true, then the existing file is deleted before the move operation."
+ },
+ "forceWrites": {
+ "kind": "parameter",
+ "displayName": "Force Writes",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Whether to force syncing writes to the file system. You can turn this off if you do not want this level of guarantee, for example if writing to logs / audit logs etc; this would yield better performance."
+ },
+ "keepLastModified": {
+ "kind": "parameter",
+ "displayName": "Keep Last Modified",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Will keep the last modified timestamp from the source file (if any). Will use the Exchange.FILE_LAST_MODIFIED header to located the timestamp. This header can contain either a java.util.Date or long with the timestamp. If the timestamp exists and the option is enabled it will set this timestamp on the written file. Note: This option only applies to the file producer. You cannot use this option with any of the ftp producers."
+ },
+ "moveExistingFileStrategy": {
+ "kind": "parameter",
+ "displayName": "Move Existing File Strategy",
+ "group": "producer (advanced)",
+ "label": "producer,advanced",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.component.file.strategy.FileMoveExistingStrategy",
+ "deprecated": false,
+ "secret": false,
+ "description": "Strategy (Custom Strategy) used to move file with special naming token to use when fileExist\u003dMove is configured. By default, there is an implementation used if no custom strategy is provided"
+ },
+ "autoCreate": {
+ "kind": "parameter",
+ "displayName": "Auto Create",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Automatically create missing directories in the file\u0027s pathname. For the file consumer, that means creating the starting directory. For the file producer, it means the directory the files should be written to."
+ },
+ "basicPropertyBinding": {
+ "kind": "parameter",
+ "displayName": "Basic Property Binding",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities"
+ },
+ "bufferSize": {
+ "kind": "parameter",
+ "displayName": "Buffer Size",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "131072",
+ "description": "Buffer size in bytes used for writing files (or in case of FTP for downloading and uploading files)."
+ },
+ "copyAndDeleteOnRenameFail": {
+ "kind": "parameter",
+ "displayName": "Copy And Delete On Rename Fail",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Whether to fallback and do a copy and delete file, in case the file could not be renamed directly. This option is not available for the FTP component."
+ },
+ "renameUsingCopy": {
+ "kind": "parameter",
+ "displayName": "Rename Using Copy",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Perform rename operations using a copy and delete strategy. This is primarily used in environments where the regular rename operation is unreliable (e.g. across different file systems or networks). This option takes precedence over the copyAndDeleteOnRenameFail parameter that will automatically fall back to the copy and delete strategy, but only after additional delays."
+ },
+ "synchronous": {
+ "kind": "parameter",
+ "displayName": "Synchronous",
+ "group": "advanced",
+ "label": "advanced",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "false",
+ "description": "Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported)."
+ },
+ "antExclude": {
+ "kind": "parameter",
+ "displayName": "Ant Exclude",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Ant style filter exclusion. If both antInclude and antExclude are used, antExclude takes precedence over antInclude. Multiple exclusions may be specified in comma-delimited format."
+ },
+ "antFilterCaseSensitive": {
+ "kind": "parameter",
+ "displayName": "Ant Filter Case Sensitive",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Sets case sensitive flag on ant filter."
+ },
+ "antInclude": {
+ "kind": "parameter",
+ "displayName": "Ant Include",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Ant style filter inclusion. Multiple inclusions may be specified in comma-delimited format."
+ },
+ "eagerMaxMessagesPerPoll": {
+ "kind": "parameter",
+ "displayName": "Eager Max Messages Per Poll",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Allows for controlling whether the limit from maxMessagesPerPoll is eager or not. If eager then the limit is during the scanning of files. Where as false would scan all files, and then perform sorting. Setting this option to false allows for sorting all files first, and then limit the poll. Mind that this requires a higher memory usage as all file details are in memory to perform the sorting."
+ },
+ "exclude": {
+ "kind": "parameter",
+ "displayName": "Exclude",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Is used to exclude files, if filename matches the regex pattern (matching is case in-senstive). Notice if you use symbols such as plus sign and others you would need to configure this using the RAW() syntax if configuring this as an endpoint uri. See more details at configuring endpoint uris"
+ },
+ "filter": {
+ "kind": "parameter",
+ "displayName": "Filter",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.component.file.GenericFileFilter\u003cjava.io.File\u003e",
+ "deprecated": false,
+ "secret": false,
+ "description": "Pluggable filter as a org.apache.camel.component.file.GenericFileFilter class. Will skip files if filter returns false in its accept() method."
+ },
+ "filterDirectory": {
+ "kind": "parameter",
+ "displayName": "Filter Directory",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Filters the directory based on Simple language. For example to filter on current date, you can use a simple date pattern such as ${date:now:yyyMMdd}"
+ },
+ "filterFile": {
+ "kind": "parameter",
+ "displayName": "Filter File",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Filters the file based on Simple language. For example to filter on file size, you can use ${file:size} 5000"
+ },
+ "idempotent": {
+ "kind": "parameter",
+ "displayName": "Idempotent",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "boolean",
+ "javaType": "java.lang.Boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "false",
+ "description": "Option to use the Idempotent Consumer EIP pattern to let Camel skip already processed files. Will by default use a memory based LRUCache that holds 1000 entries. If noop\u003dtrue then idempotent will be enabled as well to avoid consuming the same files over and over again."
+ },
+ "idempotentKey": {
+ "kind": "parameter",
+ "displayName": "Idempotent Key",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "To use a custom idempotent key. By default the absolute path of the file is used. You can use the File Language, for example to use the file name and file size, you can do: idempotentKey\u003d${file:name}-${file:size}"
+ },
+ "idempotentRepository": {
+ "kind": "parameter",
+ "displayName": "Idempotent Repository",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.spi.IdempotentRepository",
+ "deprecated": false,
+ "secret": false,
+ "description": "A pluggable repository org.apache.camel.spi.IdempotentRepository which by default use MemoryMessageIdRepository if none is specified and idempotent is true."
+ },
+ "include": {
+ "kind": "parameter",
+ "displayName": "Include",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Is used to include files, if filename matches the regex pattern (matching is case in-sensitive). Notice if you use symbols such as plus sign and others you would need to configure this using the RAW() syntax if configuring this as an endpoint uri. See more details at configuring endpoint uris"
+ },
+ "maxDepth": {
+ "kind": "parameter",
+ "displayName": "Max Depth",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "2147483647",
+ "description": "The maximum depth to traverse when recursively processing a directory."
+ },
+ "maxMessagesPerPoll": {
+ "kind": "parameter",
+ "displayName": "Max Messages Per Poll",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "To define a maximum messages to gather per poll. By default no maximum is set. Can be used to set a limit of e.g. 1000 to avoid when starting up the server that there are thousands of files. Set a value of 0 or negative to disabled it. Notice: If this option is in use then the File and FTP components will limit before any sorting. For example if you have 100000 files and use maxMessagesPerPoll\u003d500, then only the first 500 files will be picked up, and then sorted. You can use the eagerMaxMessagesPerPoll option and set this to false to allow to scan all files first and then sort afterwards."
+ },
+ "minDepth": {
+ "kind": "parameter",
+ "displayName": "Min Depth",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "The minimum depth to start processing when recursively processing a directory. Using minDepth\u003d1 means the base directory. Using minDepth\u003d2 means the first sub directory."
+ },
+ "move": {
+ "kind": "parameter",
+ "displayName": "Move",
+ "group": "filter",
+ "label": "consumer,filter",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Expression (such as Simple Language) used to dynamically set the filename when moving it after processing. To move files into a .done subdirectory just enter .done."
+ },
+ "exclusiveReadLockStrategy": {
+ "kind": "parameter",
+ "displayName": "Exclusive Read Lock Strategy",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy\u003cjava.io.File\u003e",
+ "deprecated": false,
+ "secret": false,
+ "description": "Pluggable read-lock as a org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy implementation."
+ },
+ "readLock": {
+ "kind": "parameter",
+ "displayName": "Read Lock",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "enum": [
+ "none",
+ "markerFile",
+ "fileLock",
+ "rename",
+ "changed",
+ "idempotent",
+ "idempotent-changed",
+ "idempotent-rename"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "none",
+ "description": "Used by consumer, to only poll the files if it has exclusive read-lock on the file (i.e. the file is not in-progress or being written). Camel will wait until the file lock is granted. This option provides the build in strategies: - none - No read lock is in use - markerFile - Camel creates a marker file (fileName.camelLock) and then holds a lock on it. This option is not available for the FTP component - changed - Changed is using file length/modification timestamp to detect whether the file is currently being copied or not. Will at least use 1 sec to determine this, so this option cannot consume files as fast as the others, but can be more reliable as the JDK IO API cannot always determine whether a file is currently being used by another process. The option readLockCheckInterval can be used to set the check frequency. - fileLock - is for using java.nio.channels.FileLock. This option is not avail for Windows OS and the FTP component. This approach should be avoided when accessing a remote file system via a mount/share unless that file system supports distributed file locks. - rename - rename is for using a try to rename the file as a test if we can get exclusive read-lock. - idempotent - (only for file component) idempotent is for using a idempotentRepository as the read-lock. This allows to use read locks that supports clustering if the idempotent repository implementation supports that. - idempotent-changed - (only for file component) idempotent-changed is for using a idempotentRepository and changed as the combined read-lock. This allows to use read locks that supports clustering if the idempotent repository implementation supports that. - idempotent-rename - (only for file component) idempotent-rename is for using a idempotentRepository and rename as the combined read-lock. This allows to use read locks that supports clustering if the idempotent repository implementation supports that.Notice: The various read locks is not all suited to work in clustered mode, where concurrent consumers on different nodes is competing for the same files on a shared file system. The markerFile using a close to atomic operation to create the empty marker file, but its not guaranteed to work in a cluster. The fileLock may work better but then the file system need to support distributed file locks, and so on. Using the idempotent read lock can support clustering if the idempotent repository supports clustering, such as Hazelcast Component or Infinispan."
+ },
+ "readLockCheckInterval": {
+ "kind": "parameter",
+ "displayName": "Read Lock Check Interval",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "1000",
+ "description": "Interval in millis for the read-lock, if supported by the read lock. This interval is used for sleeping between attempts to acquire the read lock. For example when using the changed read lock, you can set a higher interval period to cater for slow writes. The default of 1 sec. may be too fast if the producer is very slow writing the file. Notice: For FTP the default readLockCheckInterval is 5000. The readLockTimeout value must be higher than readLockCheckInterval, but a rule of thumb is to have a timeout that is at least 2 or more times higher than the readLockCheckInterval. This is needed to ensure that amble time is allowed for the read lock process to try to grab the lock before the timeout was hit."
+ },
+ "readLockDeleteOrphanLockFiles": {
+ "kind": "parameter",
+ "displayName": "Read Lock Delete Orphan Lock Files",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Whether or not read lock with marker files should upon startup delete any orphan read lock files, which may have been left on the file system, if Camel was not properly shutdown (such as a JVM crash). If turning this option to false then any orphaned lock file will cause Camel to not attempt to pickup that file, this could also be due another node is concurrently reading files from the same shared directory."
+ },
+ "readLockIdempotentReleaseAsync": {
+ "kind": "parameter",
+ "displayName": "Read Lock Idempotent Release Async",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "Whether the delayed release task should be synchronous or asynchronous. See more details at the readLockIdempotentReleaseDelay option."
+ },
+ "readLockIdempotentReleaseAsyncPoolSize": {
+ "kind": "parameter",
+ "displayName": "Read Lock Idempotent Release Async Pool Size",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "The number of threads in the scheduled thread pool when using asynchronous release tasks. Using a default of 1 core threads should be sufficient in almost all use-cases, only set this to a higher value if either updating the idempotent repository is slow, or there are a lot of files to process. This option is not in-use if you use a shared thread pool by configuring the readLockIdempotentReleaseExecutorService option. See more details at the readLockIdempotentReleaseDelay option."
+ },
+ "readLockIdempotentReleaseDelay": {
+ "kind": "parameter",
+ "displayName": "Read Lock Idempotent Release Delay",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "Whether to delay the release task for a period of millis. This can be used to delay the release tasks to expand the window when a file is regarded as read-locked, in an active/active cluster scenario with a shared idempotent repository, to ensure other nodes cannot potentially scan and acquire the same file, due to race-conditions. By expanding the time-window of the release tasks helps prevents these situations. Note delaying is only needed if you have configured readLockRemoveOnCommit to true."
+ },
+ "readLockIdempotentReleaseExecutorService": {
+ "kind": "parameter",
+ "displayName": "Read Lock Idempotent Release Executor Service",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "object",
+ "javaType": "java.util.concurrent.ScheduledExecutorService",
+ "deprecated": false,
+ "secret": false,
+ "description": "To use a custom and shared thread pool for asynchronous release tasks. See more details at the readLockIdempotentReleaseDelay option."
+ },
+ "readLockLoggingLevel": {
+ "kind": "parameter",
+ "displayName": "Read Lock Logging Level",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.LoggingLevel",
+ "enum": [
+ "TRACE",
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "OFF"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "DEBUG",
+ "description": "Logging level used when a read lock could not be acquired. By default a DEBUG is logged. You can change this level, for example to OFF to not have any logging. This option is only applicable for readLock of types: changed, fileLock, idempotent, idempotent-changed, idempotent-rename, rename."
+ },
+ "readLockMarkerFile": {
+ "kind": "parameter",
+ "displayName": "Read Lock Marker File",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Whether to use marker file with the changed, rename, or exclusive read lock types. By default a marker file is used as well to guard against other processes picking up the same files. This behavior can be turned off by setting this option to false. For example if you do not want to write marker files to the file systems by the Camel application."
+ },
+ "readLockMinAge": {
+ "kind": "parameter",
+ "displayName": "Read Lock Min Age",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "0",
+ "description": "This option is applied only for readLock\u003dchanged. It allows to specify a minimum age the file must be before attempting to acquire the read lock. For example use readLockMinAge\u003d300s to require the file is at last 5 minutes old. This can speedup the changed read lock as it will only attempt to acquire files which are at least that given age."
+ },
+ "readLockMinLength": {
+ "kind": "parameter",
+ "displayName": "Read Lock Min Length",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "1",
+ "description": "This option is applied only for readLock\u003dchanged. It allows you to configure a minimum file length. By default Camel expects the file to contain data, and thus the default value is 1. You can set this option to zero, to allow consuming zero-length files."
+ },
+ "readLockRemoveOnCommit": {
+ "kind": "parameter",
+ "displayName": "Read Lock Remove On Commit",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "This option is applied only for readLock\u003didempotent. It allows to specify whether to remove the file name entry from the idempotent repository when processing the file is succeeded and a commit happens. By default the file is not removed which ensures that any race-condition do not occur so another active node may attempt to grab the file. Instead the idempotent repository may support eviction strategies that you can configure to evict the file name entry after X minutes - this ensures no problems with race conditions. See more details at the readLockIdempotentReleaseDelay option."
+ },
+ "readLockRemoveOnRollback": {
+ "kind": "parameter",
+ "displayName": "Read Lock Remove On Rollback",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "This option is applied only for readLock\u003didempotent. It allows to specify whether to remove the file name entry from the idempotent repository when processing the file failed and a rollback happens. If this option is false, then the file name entry is confirmed (as if the file did a commit)."
+ },
+ "readLockTimeout": {
+ "kind": "parameter",
+ "displayName": "Read Lock Timeout",
+ "group": "lock",
+ "label": "consumer,lock",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "10000",
+ "description": "Optional timeout in millis for the read-lock, if supported by the read-lock. If the read-lock could not be granted and the timeout triggered, then Camel will skip the file. At next poll Camel, will try the file again, and this time maybe the read-lock could be granted. Use a value of 0 or lower to indicate forever. Currently fileLock, changed and rename support the timeout. Notice: For FTP the default readLockTimeout value is 20000 instead of 10000. The readLockTimeout value must be higher than readLockCheckInterval, but a rule of thumb is to have a timeout that is at least 2 or more times higher than the readLockCheckInterval. This is needed to ensure that amble time is allowed for the read lock process to try to grab the lock before the timeout was hit."
+ },
+ "backoffErrorThreshold": {
+ "kind": "parameter",
+ "displayName": "Backoff Error Threshold",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in."
+ },
+ "backoffIdleThreshold": {
+ "kind": "parameter",
+ "displayName": "Backoff Idle Threshold",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in."
+ },
+ "backoffMultiplier": {
+ "kind": "parameter",
+ "displayName": "Backoff Multiplier",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "integer",
+ "javaType": "int",
+ "deprecated": false,
+ "secret": false,
+ "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and/or backoffErrorThreshold must also be configured."
+ },
+ "delay": {
+ "kind": "parameter",
+ "displayName": "Delay",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "500",
+ "description": "Milliseconds before the next poll."
+ },
+ "greedy": {
+ "kind": "parameter",
+ "displayName": "Greedy",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages."
+ },
+ "initialDelay": {
+ "kind": "parameter",
+ "displayName": "Initial Delay",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "1000",
+ "description": "Milliseconds before the first poll starts."
+ },
+ "repeatCount": {
+ "kind": "parameter",
+ "displayName": "Repeat Count",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "integer",
+ "javaType": "long",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "0",
+ "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever."
+ },
+ "runLoggingLevel": {
+ "kind": "parameter",
+ "displayName": "Run Logging Level",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "object",
+ "javaType": "org.apache.camel.LoggingLevel",
+ "enum": [
+ "TRACE",
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "OFF"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "TRACE",
+ "description": "The consumer logs a start/complete log line when it polls. This option allows you to configure the logging level for that."
+ },
+ "scheduledExecutorService": {
+ "kind": "parameter",
+ "displayName": "Scheduled Executor Service",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "object",
+ "javaType": "java.util.concurrent.ScheduledExecutorService",
+ "deprecated": false,
+ "secret": false,
+ "description": "Allows for configuring a custom/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool."
+ },
+ "scheduler": {
+ "kind": "parameter",
+ "displayName": "Scheduler",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "enum": [
+ "none",
+ "spring",
+ "quartz"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "none",
+ "description": "To use a cron scheduler from either camel-spring or camel-quartz component"
+ },
+ "schedulerProperties": {
+ "kind": "parameter",
+ "displayName": "Scheduler Properties",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "object",
+ "javaType": "java.util.Map\u003cjava.lang.String, java.lang.Object\u003e",
+ "prefix": "scheduler.",
+ "multiValue": true,
+ "deprecated": false,
+ "secret": false,
+ "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler."
+ },
+ "startScheduler": {
+ "kind": "parameter",
+ "displayName": "Start Scheduler",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Whether the scheduler should be auto started."
+ },
+ "timeUnit": {
+ "kind": "parameter",
+ "displayName": "Time Unit",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "object",
+ "javaType": "java.util.concurrent.TimeUnit",
+ "enum": [
+ "NANOSECONDS",
+ "MICROSECONDS",
+ "MILLISECONDS",
+ "SECONDS",
+ "MINUTES",
+ "HOURS",
+ "DAYS"
+ ],
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "MILLISECONDS",
+ "description": "Time unit for initialDelay and delay options."
+ },
+ "useFixedDelay": {
+ "kind": "parameter",
+ "displayName": "Use Fixed Delay",
+ "group": "scheduler",
+ "label": "consumer,scheduler",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": "true",
+ "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details."
+ },
+ "shuffle": {
+ "kind": "parameter",
+ "displayName": "Shuffle",
+ "group": "sort",
+ "label": "consumer,sort",
+ "required": false,
+ "type": "boolean",
+ "javaType": "boolean",
+ "deprecated": false,
+ "secret": false,
+ "defaultValue": false,
+ "description": "To shuffle the list of files (sort in random order)"
+ },
+ "sortBy": {
+ "kind": "parameter",
+ "displayName": "Sort By",
+ "group": "sort",
+ "label": "consumer,sort",
+ "required": false,
+ "type": "string",
+ "javaType": "java.lang.String",
+ "deprecated": false,
+ "secret": false,
+ "description": "Built-in sort by using the File Language. Supports nested sorts, so you can have a sort by file name and as a 2nd group sort by modified date."
+ },
+ "sorter": {
+ "kind": "parameter",
+ "displayName": "Sorter",
+ "group": "sort",
+ "label": "consumer,sort",
+ "required": false,
+ "type": "object",
+ "javaType": "java.util.Comparator\u003corg.apache.camel.component.file.GenericFile\u003cjava.io.File\u003e\u003e",
+ "deprecated": false,
+ "secret": false,
+ "description": "Pluggable sorter as a java.util.Comparator class."
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/templates/file-adapter/init.ftl b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/templates/file-adapter/init.ftl
new file mode 100644
index 00000000..df1a1f3c
--- /dev/null
+++ b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/ru/entaxy/templates/file-adapter/init.ftl
@@ -0,0 +1,47 @@
+[#ftl attributes={"generated.type":"blueprint"}]
+[#--
+
+ ~~~~~~licensing~~~~~~
+ file-adapter
+ ==========
+ Copyright (C) 2020 - 2021 EmDev LLC
+ ==========
+ 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.
+ ~~~~~~/licensing~~~~~~
+
+--]
+
+
+
+
+
+
+
+
+
+
+ [#if properties??]
+ [#list properties as key, value]
+ [#if !key?starts_with("##") && !key?starts_with("__")] [#-- we skip additional properties --]
+
+ [/#if]
+ [/#list]
+ [/#if]
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/template/init.ftl b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/template/init.ftl
index aff7c93d..5896815d 100644
--- a/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/template/init.ftl
+++ b/platform/runtime/base/connecting/adapter/file-adapter/src/main/resources/template/init.ftl
@@ -45,7 +45,7 @@
-
+
[#if connection.properties??]
[#list connection.properties as key, value]
diff --git a/platform/runtime/base/connecting/adapter/h2-adapter/pom.xml b/platform/runtime/base/connecting/adapter/h2-adapter/pom.xml
index 8438ad66..e95c4045 100644
--- a/platform/runtime/base/connecting/adapter/h2-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/h2-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/h2-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/h2-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index b287e1c3..da3898b0 100644
--- a/platform/runtime/base/connecting/adapter/h2-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/h2-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -110,7 +110,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${dataSourceName}"
+ "expression": "${dataSourceName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/jms-adapter/pom.xml b/platform/runtime/base/connecting/adapter/jms-adapter/pom.xml
index 3c2d802b..d3530a6d 100644
--- a/platform/runtime/base/connecting/adapter/jms-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/jms-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/jms-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/jms-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index d7a9c40a..1116fab9 100644
--- a/platform/runtime/base/connecting/adapter/jms-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/jms-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -665,7 +665,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${destinationType}:${destinationName}"
+ "expression": "${destinationType}:${destinationName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/pom.xml b/platform/runtime/base/connecting/adapter/pom.xml
index c31c77b7..2a1986b8 100644
--- a/platform/runtime/base/connecting/adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base
connecting
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/postgresql-adapter/pom.xml b/platform/runtime/base/connecting/adapter/postgresql-adapter/pom.xml
index 5e1ce99e..ca3be274 100644
--- a/platform/runtime/base/connecting/adapter/postgresql-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/postgresql-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/postgresql-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/postgresql-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index 48a13f3a..dfb5f23a 100644
--- a/platform/runtime/base/connecting/adapter/postgresql-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/postgresql-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -110,7 +110,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${dataSourceName}"
+ "expression": "${dataSourceName}"
}
},
{
diff --git a/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/pom.xml b/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/pom.xml
index f7b3d145..c324042f 100644
--- a/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/pom.xml
+++ b/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
adapter
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json b/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
index 379ef8c4..9dc44170 100644
--- a/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
+++ b/platform/runtime/base/connecting/adapter/rabbitmq-amqp-adapter/src/main/resources/ru/entaxy/adapter/metadata.json
@@ -55,7 +55,7 @@
"type": "pathParameter",
"generator": "",
"config": {
- "expession": "${destinationType}:${destinationName}"
+ "expression": "${destinationType}:${destinationName}"
}
},
{
diff --git a/platform/runtime/base/connecting/connection/pom.xml b/platform/runtime/base/connecting/connection/pom.xml
index 5f0a8f51..4784f7a0 100644
--- a/platform/runtime/base/connecting/connection/pom.xml
+++ b/platform/runtime/base/connecting/connection/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base
connecting
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/generator/common-templates-collection/pom.xml b/platform/runtime/base/connecting/generator/common-templates-collection/pom.xml
index fb88e28c..b716b3ed 100644
--- a/platform/runtime/base/connecting/generator/common-templates-collection/pom.xml
+++ b/platform/runtime/base/connecting/generator/common-templates-collection/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
generator
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.base.connecting.generator
common-templates-collection
diff --git a/platform/runtime/base/connecting/generator/ftl-generator/pom.xml b/platform/runtime/base/connecting/generator/ftl-generator/pom.xml
index 346a1f2c..a64365f4 100644
--- a/platform/runtime/base/connecting/generator/ftl-generator/pom.xml
+++ b/platform/runtime/base/connecting/generator/ftl-generator/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
generator
- 1.8.1
+ 1.8.2
4.0.0
@@ -20,7 +20,6 @@
ru.entaxy.esb.platform.runtime.base.connecting.generator.ftl
- 2.3.29
diff --git a/platform/runtime/base/connecting/generator/ftl-generator/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/ftl/FTLGenerator.java b/platform/runtime/base/connecting/generator/ftl-generator/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/ftl/FTLGenerator.java
index cd469a55..de52563f 100644
--- a/platform/runtime/base/connecting/generator/ftl-generator/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/ftl/FTLGenerator.java
+++ b/platform/runtime/base/connecting/generator/ftl-generator/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/ftl/FTLGenerator.java
@@ -105,6 +105,22 @@ public class FTLGenerator extends AbstractSelfPublishGenerator
return generateForTemplate(template, properties);
}
+ @Override
+ public boolean isGeneratable(Map properties) throws Exception {
+ prepareTemplate(properties);
+ if (template == null)
+ return false;
+ URL templateURL = template.getTemplateLocation()==null
+ ?FrameworkUtil.getBundle(FTLGenerator.class).getEntry(DEFAULT_TEMPLATE_PATH)
+ :template.getTemplateLocation();
+ try {
+ Template temp = getTemplateByFullName(templateURL, template.getTemplateFullName());
+ return (temp != null);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
public Generated generateForTemplate(ru.entaxy.base.generator.template.Template template,
Map properties) throws Exception {
@@ -194,19 +210,19 @@ public class FTLGenerator extends AbstractSelfPublishGenerator
if (this.template != null)
return;
- Map finalPropertes = new HashMap<>();
- finalPropertes.putAll(initialProperties);
- finalPropertes.putAll(generationProperties);
+ Map finalProperties = new HashMap<>();
+ finalProperties.putAll(initialProperties);
+ finalProperties.putAll(generationProperties);
TemplateImpl temp = new TemplateImpl();
temp.setBundleContext(
- (BundleContext)finalPropertes.getOrDefault(Generator.PROP_TARGET_BUNDLE_CONTEXT
+ (BundleContext)finalProperties.getOrDefault(Generator.PROP_TARGET_BUNDLE_CONTEXT
, FrameworkUtil.getBundle(FTLGenerator.class).getBundleContext())
);
- temp.setTemplateName((String)finalPropertes.getOrDefault(PROP_TEMPLATE_NAME
- , (String)finalPropertes.getOrDefault(Generator.PROP_USAGE_TYPE
+ temp.setTemplateName((String)finalProperties.getOrDefault(PROP_TEMPLATE_NAME
+ , (String)finalProperties.getOrDefault(Generator.PROP_USAGE_TYPE
, "root")));
- temp.setPath((String)finalPropertes.getOrDefault(PROP_TEMPLATE_NAME
+ temp.setPath((String)finalProperties.getOrDefault(PROP_TEMPLATE_NAME
, DEFAULT_TEMPLATE_PATH)
);
diff --git a/platform/runtime/base/connecting/generator/generator-api/pom.xml b/platform/runtime/base/connecting/generator/generator-api/pom.xml
index ce49e0ae..15dcd304 100644
--- a/platform/runtime/base/connecting/generator/generator-api/pom.xml
+++ b/platform/runtime/base/connecting/generator/generator-api/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
generator
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/Template.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/Template.java
index ee86d45e..e1dd388b 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/Template.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/Template.java
@@ -20,6 +20,7 @@
package ru.entaxy.base.generator.template;
import java.net.URL;
+import java.util.Map;
public interface Template {
@@ -29,5 +30,5 @@ public interface Template {
public String getTemplateName();
public String getTemplateFileName();
public String getTemplateFullName();
-
+ public Map getAdditionalProperties();
}
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateImpl.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateImpl.java
index 0396a930..2792e3bf 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateImpl.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateImpl.java
@@ -21,6 +21,7 @@ package ru.entaxy.base.generator.template;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Map;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
@@ -45,6 +46,8 @@ public class TemplateImpl implements Template {
protected String templateLocation;
+ protected Map additionalProperties = null;
+
public void load(ProvidedTemplate providedTemplate) {
id = providedTemplate.getId();
name = providedTemplate.getName();
@@ -55,6 +58,7 @@ public class TemplateImpl implements Template {
if (!path.endsWith("/"))
path += "/";
description = providedTemplate.getDescription();
+ additionalProperties = providedTemplate.getAdditionalProperties();
}
@Override
@@ -120,5 +124,13 @@ public class TemplateImpl implements Template {
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
+
+ public Map getAdditionalProperties() {
+ return additionalProperties;
+ }
+
+ public void setAdditionalProperties(Map additionalProperties) {
+ this.additionalProperties = additionalProperties;
+ }
}
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateService.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateService.java
index 80377e4b..4c842f75 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateService.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/TemplateService.java
@@ -25,6 +25,7 @@ public interface TemplateService {
public static final String TEMPLATE_PROVIDER_HEADER = "Entaxy-Template-Provider";
+ public static final String PROP_PREFIX = "template.";
public static final String PROP_ID = "template.id";
public static final String PROP_TYPE = "template.type";
public static final String PROP_NAME = "template.name";
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/LegacyTemplateAdapter.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/LegacyTemplateAdapter.java
index 99310363..d7b953d2 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/LegacyTemplateAdapter.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/LegacyTemplateAdapter.java
@@ -84,6 +84,11 @@ public class LegacyTemplateAdapter {
public String getTemplateFullName() {
return template.getTemplateFileName() + ".ftl";
}
+
+ @Override
+ public Map getAdditionalProperties() {
+ return null;
+ }
}
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/ProvidedTemplate.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/ProvidedTemplate.java
index c7eda268..9d435eae 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/ProvidedTemplate.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/ProvidedTemplate.java
@@ -19,6 +19,8 @@
*/
package ru.entaxy.base.generator.template.impl;
+import java.util.Map;
+
import org.osgi.framework.ServiceRegistration;
import ru.entaxy.base.generator.template.Template;
@@ -32,6 +34,7 @@ public class ProvidedTemplate {
protected String type;
protected String path;
protected String description;
+ protected Map additionalProperties = null;
public ServiceRegistration registration;
@@ -47,6 +50,7 @@ public class ProvidedTemplate {
this.type = templateMetadata.getType();
this.path = templateMetadata.getPath();
this.description = templateMetadata.getDescription();
+ this.additionalProperties = templateMetadata.getAdditionalProperties();
}
public String getId() {
@@ -104,6 +108,14 @@ public class ProvidedTemplate {
public void setDescription(String description) {
this.description = description;
}
+
+ public Map getAdditionalProperties() {
+ return additionalProperties;
+ }
+
+ public void setAdditionalProperties(Map additionalProperties) {
+ this.additionalProperties = additionalProperties;
+ }
}
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateBundleTrackerCustomizer.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateBundleTrackerCustomizer.java
index 0b1da56e..6b851251 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateBundleTrackerCustomizer.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateBundleTrackerCustomizer.java
@@ -24,9 +24,9 @@ import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Dictionary;
+import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Optional;
-import java.util.Properties;
import java.util.stream.Collectors;
import org.osgi.framework.Bundle;
@@ -93,29 +93,77 @@ public class TemplateBundleTrackerCustomizer implements BundleTrackerCustomizer<
if (!isTemplateProvider)
return null;
+// Enumeration entries = bundle.getEntryPaths(TemplateProvider.TEMPLATE_PATH + "/metadata.json");
URL metadataUrl = bundle.getEntry(TemplateProvider.TEMPLATE_PATH + "/metadata.json");
- String metadata = new BufferedReader (
- new InputStreamReader(
- metadataUrl.openStream(), StandardCharsets.UTF_8))
- .lines()
- .collect(Collectors.joining("\n"));
- GsonBuilder builder = new GsonBuilder();
- Gson gson = builder.create();
-
- JsonElement je = (new JsonParser()).parse(metadata);
- JsonObject root = je.getAsJsonObject();
-
- JsonElement templatesElement = root.get("templates");
- if (templatesElement == null)
- return null;
- if (!templatesElement.isJsonArray())
- return null;
- JsonArray templates = templatesElement.getAsJsonArray();
- for (int i=0; i foundEntries = bundle.findEntries(TemplateProvider.TEMPLATE_PATH, "*.*", true);
+ while (foundEntries.hasMoreElements()) {
+ URL entry = foundEntries.nextElement();
+ log.debug("FOUND :: " + entry.toString());
+ if (entry.toString().endsWith("/")) {
+ log.debug(":: .. is folder");
+ continue;
+ }
+ String localPath = entry.toString();
+ localPath = localPath.substring(localPath.indexOf(TemplateProvider.TEMPLATE_PATH) + TemplateProvider.TEMPLATE_PATH.length() + 1);
+ String fullname = localPath.substring(localPath.lastIndexOf("/")+1);
+ String path = localPath.lastIndexOf("/")>=0
+ ?localPath.substring(0, localPath.lastIndexOf("/"))
+ :"";
+ String fullPath = TemplateProvider.TEMPLATE_PATH + "/" + path;
+ String fileName = fullname.substring(0, fullname.lastIndexOf("."));
+ String fileType = fullname.substring(fullname.lastIndexOf(".")+1);
+ String id = path.replace("/", ".")
+ + (path.isEmpty()?"":".")
+ + fileName;
+ log.debug(":: localPath = " + localPath + "; fullName = " + fullname + "; fileName = " + fileName
+ + "; fileType = " + fileType + "; path = " + path);
+
+ TemplateMetadata meta = new TemplateMetadata();
+ meta.setId(id);
+ meta.setFilename(fileName);
+ meta.setFullname(fullname);
+ meta.setName(id);
+ meta.setType(fileType);
+ meta.setPath(fullPath);
+ meta.setDescription("Found in bundle [" + bundle.getBundleId() + "] on path [" + localPath + "]");
+ ProvidedTemplate providedTemplate = new ProvidedTemplate(meta);
+ result.providedTemplates.add(providedTemplate);
+ }
+
+ log.debug("END :: Searching for templates in " + bundle.getBundleId());
}
return result;
@@ -135,6 +183,9 @@ public class TemplateBundleTrackerCustomizer implements BundleTrackerCustomizer<
props.put(TemplateService.PROP_NAME, provided.getName());
props.put(TemplateService.PROP_TYPE, provided.getType());
props.put(TemplateService.PROP_DESCRIPTION, provided.getDescription());
+ if (provided.getAdditionalProperties() != null) {
+ provided.getAdditionalProperties().forEach((k,v) -> {props.put(TemplateService.PROP_PREFIX + k, v);});
+ }
ServiceRegistration registration =
templateProvider.bundleContext.registerService(
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateMetadata.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateMetadata.java
index 45d1dc88..a11453f9 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateMetadata.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/base/generator/template/impl/TemplateMetadata.java
@@ -19,6 +19,7 @@
*/
package ru.entaxy.base.generator.template.impl;
+import java.util.Map;
import java.util.UUID;
import ru.entaxy.platform.base.support.CommonUtils;
@@ -32,6 +33,7 @@ public class TemplateMetadata {
protected String fullname;
protected String path;
protected String description = "";
+ protected Map additionalProperties;
public String getId() {
return id;
@@ -93,5 +95,11 @@ public class TemplateMetadata {
public void setDescription(String description) {
this.description = description;
}
+ public Map getAdditionalProperties() {
+ return additionalProperties;
+ }
+ public void setAdditionalProperties(Map additionalProperties) {
+ this.additionalProperties = additionalProperties;
+ }
}
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generated.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generated.java
index 95cf22e4..c78b5c9c 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generated.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generated.java
@@ -29,7 +29,7 @@ public interface Generated {
public static final String GENERATED_TYPE_BLUEPRINT = "blueprint";
- public static final String GENERATED_TYPE_BLUEPRINT_NODE = "blueprint-node";
+ public static final String GENERATED_TYPE_BLUEPRINT_FRAGMENT = "blueprint.fragment";
public static Generated create() {
return new GeneratedImpl();
diff --git a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generator.java b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generator.java
index a4ab08f2..987c6da0 100644
--- a/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generator.java
+++ b/platform/runtime/base/connecting/generator/generator-api/src/main/java/ru/entaxy/esb/platform/runtime/base/connecting/generator/Generator.java
@@ -28,4 +28,5 @@ public interface Generator {
public String getGeneratorId();
public Generated generate(Map properties) throws Exception;
+ public boolean isGeneratable(Map properties) throws Exception;
}
diff --git a/platform/runtime/base/connecting/generator/generator-factory/pom.xml b/platform/runtime/base/connecting/generator/generator-factory/pom.xml
index a60f0451..8d89fc59 100644
--- a/platform/runtime/base/connecting/generator/generator-factory/pom.xml
+++ b/platform/runtime/base/connecting/generator/generator-factory/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
generator
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/generator/pom.xml b/platform/runtime/base/connecting/generator/pom.xml
index c1bb61df..fe31deba 100644
--- a/platform/runtime/base/connecting/generator/pom.xml
+++ b/platform/runtime/base/connecting/generator/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base
connecting
- 1.8.1
+ 1.8.2
4.0.0
@@ -21,5 +21,6 @@
ftl-generator
generator-factory
common-templates-collection
+ template-service-shell
\ No newline at end of file
diff --git a/platform/runtime/base/connecting/generator/template-service-shell/LICENSE.txt b/platform/runtime/base/connecting/generator/template-service-shell/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/base/connecting/generator/template-service-shell/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/base/connecting/generator/template-service-shell/pom.xml b/platform/runtime/base/connecting/generator/template-service-shell/pom.xml
new file mode 100644
index 00000000..844f4b60
--- /dev/null
+++ b/platform/runtime/base/connecting/generator/template-service-shell/pom.xml
@@ -0,0 +1,50 @@
+
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime.base.connecting
+ generator
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.base.connecting.generator
+ template-service-shell
+ bundle
+ ENTAXY :: PLATFORM :: BASE :: TEMPLATES :: SHELL
+ ENTAXY :: PLATFORM :: BASE :: TEMPLATES :: SHELL
+
+
+ NONE
+
+
+
+
+
+ org.apache.karaf
+ org.apache.karaf.util
+
+
+ org.apache.karaf.shell
+ org.apache.karaf.shell.core
+ ${karaf.version}
+
+
+
+ ru.entaxy.esb.platform.runtime.base.connecting.generator
+
+ generator-api
+ ${project.version}
+
+
+
+ ru.entaxy.esb.platform.runtime.base.connecting.generator
+
+ generator-factory
+ ${project.version}
+
+
+ ru.entaxy.esb.platform.runtime.base
+ base-support
+ ${project.version}
+
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/Generate.java b/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/Generate.java
new file mode 100644
index 00000000..99592dfb
--- /dev/null
+++ b/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/Generate.java
@@ -0,0 +1,88 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * template-service-test
+ * ==========
+ * Copyright (C) 2020 - 2021 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.base.generator.template.shell;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+import ru.entaxy.base.generator.template.Template;
+import ru.entaxy.base.generator.template.TemplateAwareGenerator;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generator;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.factory.GeneratorFactory;
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.JSONUtils;
+
+@Service
+@Command(scope = "templates", name = "generate")
+public class Generate extends TemplateServiceSupport implements Action {
+
+ @Argument(index = 0, name = "template-id", required = true)
+ String templateId;
+
+ @Argument(index = 1, name = "parameters", required = false)
+ String params;
+
+ @Override
+ public Object execute() throws Exception {
+ Template t = templateService.getTemplateById(templateId);
+ if (t == null) {
+ System.out.println("Template [" + templateId + "] not found");
+ return null;
+ }
+ TemplateAwareGenerator g = GeneratorFactory.createGenerator(t);
+ if (g == null) {
+ System.out.println("Generator for template [" + templateId + "] not found");
+ return null;
+ }
+ Generated result = null;
+ if (CommonUtils.isValid(params)) {
+ GsonBuilder builder = new GsonBuilder();
+ Gson gson = builder.create();
+
+ JsonElement je = (new JsonParser()).parse(params);
+ Map map = JSONUtils.element2map(je);
+
+ result = g.generate(t, map);
+ } else {
+ result = g.generate(t, new HashMap<>());
+ }
+ if (result == null) {
+ System.out.println("Generated is empty, template: [" + templateId + "] not found");
+ return null;
+ } else {
+ System.out.println("Generated: ");
+ System.out.println("\ttype: " + result.getType());
+ System.out.println("\tcontent: " + (result.getObject()==null?"null":"[==\n" + result.getObject().toString() + "\n==]"));
+ }
+ return null;
+ }
+
+}
diff --git a/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/ListTemplates.java b/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/ListTemplates.java
new file mode 100644
index 00000000..873a4502
--- /dev/null
+++ b/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/ListTemplates.java
@@ -0,0 +1,69 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * template-service-test
+ * ==========
+ * Copyright (C) 2020 - 2021 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.base.generator.template.shell;
+
+import java.util.Comparator;
+import java.util.stream.Collectors;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import ru.entaxy.base.generator.template.Template;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generator;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.factory.GeneratorFactory;
+
+@Service
+@Command(scope = "templates", name = "list")
+public class ListTemplates extends TemplateServiceSupport implements Action {
+
+ @Override
+ public Object execute() throws Exception {
+
+ ShellTable table = new ShellTable();
+ table.column("id");
+ table.column("File");
+ table.column("Location");
+ table.column("Generator");
+
+ for (Template t: templateService.getAllTemplates().stream().sorted(new Comparator() {
+
+ @Override
+ public int compare(Template o1, Template o2) {
+ return o1.getId().compareToIgnoreCase(o2.getId());
+ }
+
+ }).collect(Collectors.toList()) ) {
+ Generator g = (Generator)GeneratorFactory.createGenerator(t);
+ table.addRow().addContent(
+ t.getId(),
+ t.getTemplateFullName(),
+ t.getTemplateLocation()==null?"":t.getTemplateLocation().toString(),
+ (g==null?"NOT FOUND":g.getGeneratorId())
+ );
+ }
+
+ table.print(System.out);
+
+ return null;
+ }
+
+}
diff --git a/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/TemplateServiceSupport.java b/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/TemplateServiceSupport.java
new file mode 100644
index 00000000..bdb3614c
--- /dev/null
+++ b/platform/runtime/base/connecting/generator/template-service-shell/src/main/java/ru/entaxy/base/generator/template/shell/TemplateServiceSupport.java
@@ -0,0 +1,31 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * template-service-test
+ * ==========
+ * Copyright (C) 2020 - 2021 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.base.generator.template.shell;
+
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+import ru.entaxy.base.generator.template.TemplateService;
+
+public class TemplateServiceSupport {
+ @Reference
+ TemplateService templateService;
+
+
+}
diff --git a/platform/runtime/base/connecting/pom.xml b/platform/runtime/base/connecting/pom.xml
index d4e32613..fc0ef94f 100644
--- a/platform/runtime/base/connecting/pom.xml
+++ b/platform/runtime/base/connecting/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime
base
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/producer/connection-producer/pom.xml b/platform/runtime/base/connecting/producer/connection-producer/pom.xml
index 1f0d7f3f..70a2c39b 100644
--- a/platform/runtime/base/connecting/producer/connection-producer/pom.xml
+++ b/platform/runtime/base/connecting/producer/connection-producer/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
producer
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/producer/pom.xml b/platform/runtime/base/connecting/producer/pom.xml
index e8bb008f..ce674f44 100644
--- a/platform/runtime/base/connecting/producer/pom.xml
+++ b/platform/runtime/base/connecting/producer/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base
connecting
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/connecting/producer/producer-api/pom.xml b/platform/runtime/base/connecting/producer/producer-api/pom.xml
index 908e7ba3..7bb649fa 100644
--- a/platform/runtime/base/connecting/producer/producer-api/pom.xml
+++ b/platform/runtime/base/connecting/producer/producer-api/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.base.connecting
producer
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/base/management-core/pom.xml b/platform/runtime/base/management-core/pom.xml
index 83204d46..6bb16544 100644
--- a/platform/runtime/base/management-core/pom.xml
+++ b/platform/runtime/base/management-core/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime
base
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.base
management-core
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/AnnotatedMBean.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/AnnotatedMBean.java
index d733bd6b..89dc9079 100644
--- a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/AnnotatedMBean.java
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/AnnotatedMBean.java
@@ -46,7 +46,7 @@ public class AnnotatedMBean extends StandardMBean {
@Override
public MBeanInfo getMBeanInfo() {
- log.info(this.interfaceClass==null?">> INTERFACE IS NULL":">> " + this.interfaceClass.getName());
+ log.debug(this.interfaceClass==null?">> INTERFACE IS NULL":">> " + this.interfaceClass.getName());
MBeanExportPolicy policy = MBeanExportPolicy.IGNORE_ANNOTATIONS;
MBeanAnnotated anno = this.interfaceClass.getAnnotation(MBeanAnnotated.class);
if (anno != null)
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/EntaxyRuntimeTyped.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/EntaxyRuntimeTyped.java
new file mode 100644
index 00000000..935f20db
--- /dev/null
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/EntaxyRuntimeTyped.java
@@ -0,0 +1,34 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * management-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.esb.platform.base.management.core.api;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(RUNTIME)
+@Target(TYPE)
+@Inherited
+public @interface EntaxyRuntimeTyped {
+ String name() default "";
+}
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/RuntimeTypedMBean.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/RuntimeTypedMBean.java
new file mode 100644
index 00000000..74180687
--- /dev/null
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/api/RuntimeTypedMBean.java
@@ -0,0 +1,32 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * management-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.esb.platform.base.management.core.api;
+
+public interface RuntimeTypedMBean {
+
+ @Attribute(desc = "Type of Entaxy runtime object")
+ public default String getRuntimeType() {
+ if (this.getClass().isAnnotationPresent(EntaxyRuntimeTyped.class)) {
+ return ((EntaxyRuntimeTyped)this.getClass().getAnnotation(EntaxyRuntimeTyped.class)).name();
+ } else
+ return "";
+ }
+
+}
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareMBeanImpl.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareMBeanImpl.java
index e5cea673..17fe4424 100644
--- a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareMBeanImpl.java
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareMBeanImpl.java
@@ -122,7 +122,7 @@ public class BundleAwareMBeanImpl
public void refreshBundleInfo() {
Bundle b = FrameworkUtil.getBundle(getClass()).getBundleContext().getBundle(getBundleId());
- // track bundeState
+ // track bundleState
AttributeChangeTracker tracker = new AttributeChangeTracker();
tracker.oldValue(this.managedObject.getBundleState());
this.managedObject.bundleState(b.getState());
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObject.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObject.java
index 2399c274..29d9e5c4 100644
--- a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObject.java
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObject.java
@@ -39,6 +39,6 @@ public interface BundleAwareManagedObject {
BundleAwareManagedObject bundleId(long bundleId);
- BundleAwareManagedObject bundleSymbolicName(String bundleSeymbolicName);
+ BundleAwareManagedObject bundleSymbolicName(String bundleSymbolicName);
}
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObjectImpl.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObjectImpl.java
index 82d40e89..a68cf11e 100644
--- a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObjectImpl.java
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/BundleAwareManagedObjectImpl.java
@@ -98,8 +98,8 @@ public class BundleAwareManagedObjectImpl implements BundleAwareManagedObject {
}
@Override
- public BundleAwareManagedObject bundleSymbolicName(String bundleSeymbolicName) {
- setBundleSymbolicName(bundleSeymbolicName);
+ public BundleAwareManagedObject bundleSymbolicName(String bundleSymbolicName) {
+ setBundleSymbolicName(bundleSymbolicName);
return this;
}
diff --git a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/ManagedObjectDescriptor.java b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/ManagedObjectDescriptor.java
index c9aa539c..bb432ead 100644
--- a/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/ManagedObjectDescriptor.java
+++ b/platform/runtime/base/management-core/src/main/java/ru/entaxy/esb/platform/base/management/core/utils/ManagedObjectDescriptor.java
@@ -22,7 +22,7 @@ package ru.entaxy.esb.platform.base.management.core.utils;
import org.osgi.framework.ServiceRegistration;
public class ManagedObjectDescriptor {
- S object;
- C service;
- ServiceRegistration registration;
+ public S object;
+ public C service;
+ public ServiceRegistration registration;
}
diff --git a/platform/runtime/base/objects-base/LICENSE.txt b/platform/runtime/base/objects-base/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/base/objects-base/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/base/objects-base/object-factory/LICENSE.txt b/platform/runtime/base/objects-base/object-factory/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/base/objects-base/object-factory/pom.xml b/platform/runtime/base/objects-base/object-factory/pom.xml
new file mode 100644
index 00000000..e8dfd38c
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/pom.xml
@@ -0,0 +1,56 @@
+
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime.base
+ objects-base
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.base.objects-base
+ object-factory
+ bundle
+ ENTAXY :: PLATFORM :: BASE :: OBJECT FACTORING :: OBJECT FACTORY
+ ENTAXY :: PLATFORM :: BASE :: OBJECT FACTORING :: OBJECT FACTORY
+
+
+
+ ru.entaxy.platform.base.objects.factory,
+ ru.entaxy.platform.base.objects.factory.configuration,
+ ru.entaxy.platform.base.objects.factory.impl,
+ ru.entaxy.platform.base.objects.factory.tracker
+
+
+
+
+
+ com.google.code.gson
+ gson
+
+
+ org.osgi
+ org.osgi.service.component.annotations
+
+
+ org.apache.felix
+ org.apache.felix.scr
+
+
+ ru.entaxy.esb.platform.runtime.base
+ base-support
+ ${project.version}
+
+
+
+ ru.entaxy.esb.platform.runtime.base.connecting.generator
+
+ generator-api
+ ${project.version}
+
+
+
+ ru.entaxy.esb.platform.runtime.base.connecting.generator
+
+ generator-factory
+ ${project.version}
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactory.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactory.java
new file mode 100644
index 00000000..1429ec7e
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactory.java
@@ -0,0 +1,207 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gson.JsonObject;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+
+public interface EntaxyFactory extends EntaxyFactoryElements.EntaxyFactoryExtendedElement {
+
+ /*
+ * public constants, enums etc
+ */
+
+ public static interface SERVICE {
+
+ String PROP_ID = "factory.id";
+ String PROP_TYPE = "factory.type";
+ String PROP_ORIGIN_BUNDLE = "factory.origin.bundle";
+
+ }
+
+ public static interface CONFIGURATION {
+
+ String FACTORY_SECTION_NAME = "factory";
+ String FIELDS_SECTION_NAME = "fields";
+ String OUTPUTS_SECTION_NAME = "outputs";
+
+ public static interface FACTORY {
+
+ String ID = "id";
+ String TYPE = "type";
+ String DESCRIPTION = "description";
+ String LABEL = "label";
+ String CATEGORY = "category";
+
+ }
+
+ public static interface FIELDS {
+
+ public static interface REGULAR_TYPES {
+
+ String STRING = "String";
+ String BOOLEAN = "Boolean";
+ String LONG = "Long";
+ String DOUBLE = "Double";
+
+ public static Set asSet() {
+ return new HashSet<>() {{
+ add(STRING);
+ add(BOOLEAN);
+ add(DOUBLE);
+ add(LONG);
+ }};
+ }
+
+ }
+
+ public static interface ATTRIBUTES {
+
+ String FIELD_TYPE = "type";
+ String DEFAULT_VALUE = "defaultValue";
+
+ String REQUIRED = "required";
+ String IMMUTABLE = "immutable";
+
+ String IS_REF = "isRef";
+
+ }
+
+ String OBJECT_ID = "objectId";
+
+ }
+
+ public static interface OUTPUTS {
+
+ String OUTPUT_TYPE_INIT = "init";
+ String OUTPUT_TYPE_REF = "ref";
+
+ public static interface ATTRIBUTES {
+
+ String IS_DEFAULT = "isDefault";
+ String CONFIG = "config";
+ String GENERATOR = "generator";
+ String FIELDS = "fields";
+ String SCOPES = "scopes";
+
+ }
+ }
+
+ }
+
+
+ static public enum SCOPE {
+ PUBLIC("public"),
+ PROTECTED("protected"),
+ PRIVATE("private");
+
+ public String label;
+
+ private SCOPE(String label) {
+ this.label = label;
+ }
+
+ public static SCOPE valueOfLabel(String label) {
+ for (SCOPE e : values()) {
+ if (e.label.equals(label)) {
+ return e;
+ }
+ }
+ return null;
+ }
+ }
+
+ static public SCOPE DEFAULT_SCOPE = SCOPE.PUBLIC;
+
+ /*
+ * inner structure elements
+ */
+
+ public static interface OutputInfo {
+
+ public String getType();
+ public String getGenerator();
+ public List getScopes();
+ public Map getConfig();
+ public List getFields();
+ public boolean isDefault();
+
+ }
+
+ public static interface FieldInfo {
+
+ public String getName();
+ public String getType();
+ public String getDisplayName();
+ public String getDescription();
+
+ public boolean isImmutable();
+ public boolean isRequired();
+ public Object getDefaultValue();
+
+ public boolean isConditional();
+ public String getCondition();
+
+ public boolean isRef();
+ public JsonObject getJsonOrigin();
+
+ }
+
+ public static interface RefFieldInfo extends FieldInfo {
+
+ public boolean isBackRef();
+ public boolean isRefByValueOnly();
+
+ public String getRefField();
+
+ }
+
+ /*
+ * Factory itself
+ */
+
+ @Deprecated()
+ public default String getFactoryId() {
+ return getId();
+ };
+ @Deprecated
+ public default String getFactoryType() {
+ return getType();
+ };
+
+
+ public List getOutputs();
+ public OutputInfo getDefaultOutput();
+ public OutputInfo getOutputByType(String outputType);
+
+ public List getFields();
+ public List getFields(String outputType);
+
+ public Generated generate(Map parameters) throws EntaxyFactoryException ;
+ public Generated generate(String outputType, Map parameters) throws EntaxyFactoryException;
+ public Generated generate(String outputType, String scope, Map parameters) throws EntaxyFactoryException;
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactoryElements.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactoryElements.java
new file mode 100644
index 00000000..bcfff339
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactoryElements.java
@@ -0,0 +1,49 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-factory
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory;
+
+public interface EntaxyFactoryElements {
+
+ public interface EntaxyFactoryTypedElement {
+
+ String getType();
+
+ }
+
+ public interface EntaxyFactoryLabeledElement {
+
+ String getLabel();
+
+ }
+
+ public interface EntaxyFactoryCommonElement extends EntaxyFactoryTypedElement {
+
+ String getId();
+ String getDescription();
+
+ }
+
+ public interface EntaxyFactoryExtendedElement extends EntaxyFactoryCommonElement, EntaxyFactoryLabeledElement {
+
+ String getCategory();
+
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactoryException.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactoryException.java
new file mode 100644
index 00000000..7f442c59
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/EntaxyFactoryException.java
@@ -0,0 +1,24 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory;
+
+public class EntaxyFactoryException extends Exception {
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/AbstractElement.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/AbstractElement.java
new file mode 100644
index 00000000..1fca57f0
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/AbstractElement.java
@@ -0,0 +1,33 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.configuration;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+
+public abstract class AbstractElement {
+
+ @SuppressWarnings("unchecked")
+ public T fromJson(JsonElement jsonElement) {
+ Gson gson = new Gson();
+ return (T)gson.fromJson(jsonElement, this.getClass());
+ };
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/FactoryElement.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/FactoryElement.java
new file mode 100644
index 00000000..70a527d9
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/FactoryElement.java
@@ -0,0 +1,65 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.configuration;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+
+public class FactoryElement extends AbstractElement {
+
+ public static final String ELEMENT_NAME = EntaxyFactory.CONFIGURATION.FACTORY_SECTION_NAME;
+
+ protected String id;
+ protected String type;
+ protected String description;
+ protected String label;
+ protected String category;
+
+ public String getId() {
+ return id;
+ }
+ public void setId(String id) {
+ this.id = id;
+ }
+ public String getType() {
+ return type;
+ }
+ public void setType(String type) {
+ this.type = type;
+ }
+ public String getDescription() {
+ return description;
+ }
+ public void setDescription(String description) {
+ this.description = description;
+ }
+ public String getLabel() {
+ return label;
+ }
+ public void setLabel(String label) {
+ this.label = label;
+ }
+ public String getCategory() {
+ return category;
+ }
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/FieldElement.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/FieldElement.java
new file mode 100644
index 00000000..7bb051df
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/FieldElement.java
@@ -0,0 +1,168 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.configuration;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.support.JSONUtils;
+
+public class FieldElement implements EntaxyFactory.FieldInfo {
+
+ JsonObject jsonOrigin = null;
+
+ String name;
+ String type;
+ String displayName;
+ String description = "";
+
+ boolean immutable = false;
+ boolean required = false;
+ Object defaultValue = "";
+
+ boolean conditional = false;
+ String condition = null;
+
+ boolean isRef = false;
+
+ public static FieldElement merge(FieldElement...elements) {
+
+ JsonObject result = new JsonObject();
+
+ for (int i=0; i {
+
+ private static final Logger log = LoggerFactory.getLogger(FieldsElement.class);
+
+ public static final String ELEMENT_NAME = EntaxyFactory.CONFIGURATION.FIELDS_SECTION_NAME;
+
+ protected Map fields = new HashMap<>();
+
+ @Override
+ public FieldsElement fromJson(JsonElement jsonElement) {
+ Gson gson = new Gson();
+ if (jsonElement.isJsonObject()) {
+ for (Entry entry : jsonElement.getAsJsonObject().entrySet()) {
+
+ Class extends FieldElement> feClass = FieldElement.class;
+
+ if (entry.getValue().isJsonObject())
+ if (entry.getValue().getAsJsonObject().has(FIELDS.ATTRIBUTES.IS_REF)) {
+ JsonElement val = entry.getValue().getAsJsonObject().get(FIELDS.ATTRIBUTES.IS_REF);
+ if (val.isJsonPrimitive() && val.getAsJsonPrimitive().isBoolean())
+ if (val.getAsJsonPrimitive().getAsBoolean()) {
+ feClass = RefFieldElement.class;
+ }
+ }
+
+ FieldElement fe = gson.fromJson(entry.getValue(), feClass);
+ fe.setName(entry.getKey());
+ fe.setJsonOrigin(entry.getValue().isJsonObject()?entry.getValue().getAsJsonObject():new JsonObject());
+ addField(fe);
+ }
+ }
+ /*
+ * this.fields = gson.fromJson( jsonElement,
+ * TypeToken.getParameterized(ArrayList.class, FieldElement.class).getType() );
+ */
+ // processOutputs();
+ return this;
+ }
+
+ protected void addField(FieldElement fieldElement) {
+ this.fields.put(fieldElement.getName(), fieldElement);
+ }
+
+ public Map getFieldsMap(){
+ return this.fields;
+ }
+
+ public List getFields() {
+ return new ArrayList<>(fields.values());
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/OutputElement.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/OutputElement.java
new file mode 100644
index 00000000..0d279257
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/OutputElement.java
@@ -0,0 +1,231 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.configuration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.factory.GeneratorFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.FieldInfo;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.SCOPE;
+
+public class OutputElement implements EntaxyFactory.OutputInfo {
+
+ private static final Logger log = LoggerFactory.getLogger(OutputElement.class);
+
+ protected String type;
+ protected String generator = GeneratorFactory.DEFAULT_GENERATOR;
+ protected boolean isDefault = false;
+
+ protected List scopes = Arrays.asList(new String[] {EntaxyFactory.SCOPE.PUBLIC.name()});
+ protected Set supportedScopes = new HashSet<>( Arrays.asList(new SCOPE[] {EntaxyFactory.SCOPE.PUBLIC}) );
+
+ protected Map config = new HashMap<>();
+
+ protected JsonObject origin;
+
+ protected FieldsElement fields = null;
+
+ protected Map commonFields = new HashMap<>();
+
+ protected Map effectiveFields = new HashMap<>();
+
+ protected boolean isEffectiveCalculated = false;
+
+ public static OutputElement fromJson(JsonObject jsonObject) {
+ Gson gson = new Gson();
+
+ OutputElement result = gson.fromJson(jsonObject, OutputElement.class);
+ result.setOrigin(jsonObject);
+ result.updateFromOrigin();
+
+ return result;
+ }
+
+ public static OutputElement fromJson(String type, JsonObject jsonObject) {
+ OutputElement result = OutputElement.fromJson(jsonObject);
+ result.setType(type);
+ return result;
+ }
+
+ public OutputElement() {
+ super();
+ }
+
+ public void updateFromOrigin() {
+ if (origin.has(EntaxyFactory.CONFIGURATION.OUTPUTS.ATTRIBUTES.FIELDS)) {
+ JsonElement fieldsElement = origin.get(EntaxyFactory.CONFIGURATION.OUTPUTS.ATTRIBUTES.FIELDS);
+ this.fields = (new FieldsElement()).fromJson(fieldsElement);
+ }
+ if (origin.has(EntaxyFactory.CONFIGURATION.OUTPUTS.ATTRIBUTES.SCOPES)) {
+ JsonElement scopesElement = origin.get(EntaxyFactory.CONFIGURATION.OUTPUTS.ATTRIBUTES.SCOPES);
+ if (scopesElement.isJsonArray()) {
+ JsonArray ja = scopesElement.getAsJsonArray();
+ List scopes = new ArrayList<>();
+ for (int i=0; i " + getType() + " calculateEffective :: " + this.commonFields.size());
+
+ Map ownedFields;
+
+ if (fields == null) {
+ // get all common fields
+ log.debug("-> " + getType() + " taking all common fields");
+ ownedFields = Collections.emptyMap();
+ if (commonFields != null)
+ for (Entry entry: commonFields.entrySet()) {
+ this.effectiveFields.put(entry.getKey(), entry.getValue());
+ }
+
+ } else {
+ // use only locally mentioned fields
+ ownedFields = fields.getFieldsMap();
+ log.debug("->" + getType() + " ownedFields: " + fields.getFieldsMap().size());
+
+ if (commonFields != null)
+ for (Entry entry: commonFields.entrySet()) {
+ if (ownedFields.containsKey(entry.getKey())) {
+ FieldElement fe = FieldElement.merge(entry.getValue(), ownedFields.get(entry.getKey()));
+ fe.setName(entry.getKey());
+ this.effectiveFields.put(entry.getKey(), fe);
+ }
+ }
+ }
+ for (Entry entry: ownedFields.entrySet())
+ if (!this.effectiveFields.containsKey(entry.getKey()))
+ this.effectiveFields.put(entry.getKey(), entry.getValue());
+
+ this.isEffectiveCalculated = true;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String getGenerator() {
+ return generator;
+ }
+
+ @Override
+ public List getScopes() {
+ return this.supportedScopes.stream().map(s -> s.label).collect(Collectors.toList());
+ }
+
+ @Override
+ public Map getConfig() {
+ return config;
+ }
+
+ @Override
+ public List getFields() {
+ if (!this.isEffectiveCalculated)
+ calculateEffective();
+ return this.effectiveFields.values().stream().map(f->(FieldInfo)f).collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean isDefault() {
+ return isDefault;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+ public void setGenerator(String generator) {
+ this.generator = generator;
+ }
+
+ public void setScopes(String[] scopes) {
+ log.debug("\n\tsetScopes(String[] scopes)");
+ if (scopes == null) {
+ setScopes(Collections.emptyList());
+ } else {
+ setScopes(Arrays.asList(scopes));
+ }
+ }
+
+ public void setScopes(List scopes) {
+ log.debug("\n\tsetScopes(List scopes)");
+ this.scopes.clear();
+ this.supportedScopes.clear();
+ for (String s: scopes) {
+ this.scopes.add(s.toLowerCase());
+ this.supportedScopes.add(SCOPE.valueOfLabel(s));
+ }
+ }
+ public Set getSupportedScopes() {
+ return supportedScopes;
+ }
+ public boolean isScopeSupported(String scope) {
+ return isScopeSupported(SCOPE.valueOfLabel(scope));
+ }
+ public boolean isScopeSupported(SCOPE scope) {
+ return supportedScopes.contains(scope);
+ }
+ public void setDefault(boolean isDefault) {
+ this.isDefault = isDefault;
+ }
+
+ public void setConfig(Map config) {
+ this.config = config;
+ }
+
+ public JsonObject getOrigin() {
+ return origin;
+ }
+
+ public void setOrigin(JsonObject origin) {
+ this.origin = origin;
+ }
+
+ public void setCommonFields(Map commonFields) {
+ this.commonFields = commonFields;
+ this.isEffectiveCalculated = false;
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/OutputsElement.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/OutputsElement.java
new file mode 100644
index 00000000..c7d6bb4a
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/OutputsElement.java
@@ -0,0 +1,111 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.configuration;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.reflect.TypeToken;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.support.CommonUtils;
+
+public class OutputsElement extends AbstractElement {
+
+ public static final String ELEMENT_NAME = EntaxyFactory.CONFIGURATION.OUTPUTS_SECTION_NAME;
+
+ public static final String DEFAULT_OUTPUT_TYPE = "init";
+
+ // protected List outputs = new ArrayList<>();
+
+ protected Map outputsMap = new HashMap<>();
+
+ protected Map commonFields = new HashMap<>();
+
+ protected String defaultOutputType = "";
+
+ @Override
+ public OutputsElement fromJson(JsonElement jsonElement) {
+ Gson gson = new Gson();
+ /*
+ * this.outputs = gson.fromJson( jsonElement,
+ * TypeToken.getParameterized(ArrayList.class, OutputElement.class).getType() );
+ * processOutputs();
+ */
+
+ if (jsonElement.isJsonObject()) {
+ for (Entry entry: jsonElement.getAsJsonObject().entrySet()) {
+ OutputElement oe = gson.fromJson(entry.getValue(), OutputElement.class);
+ oe.setType(entry.getKey());
+ oe.setCommonFields(commonFields);
+ if (entry.getValue().isJsonObject())
+ oe.setOrigin(entry.getValue().getAsJsonObject());
+ oe.updateFromOrigin();
+ if (oe.isDefault)
+ this.defaultOutputType = oe.getType();
+ addOutput(oe);
+ }
+ }
+
+ if (!CommonUtils.isValid(defaultOutputType))
+ if (outputsMap.containsKey(DEFAULT_OUTPUT_TYPE)) {
+ this.defaultOutputType = DEFAULT_OUTPUT_TYPE;
+ this.outputsMap.get(DEFAULT_OUTPUT_TYPE).setDefault(true);
+ }
+
+ return this;
+ }
+
+ protected void addOutput(OutputElement oe) {
+ this.outputsMap.put(oe.getType(), oe);
+ }
+
+ public List getOutputs() {
+ return new ArrayList<>(outputsMap.values());
+ }
+
+ public String getDefaultOutputType() {
+ return defaultOutputType;
+ }
+
+ public void setDefaultOutputType(String defaultOutputType) {
+ this.defaultOutputType = defaultOutputType;
+ }
+
+ public boolean hasOutput(String type) {
+ return this.outputsMap.containsKey(type);
+ }
+
+ public OutputElement getOutput(String type) {
+ return this.outputsMap.get(type);
+ }
+
+ public void setCommonFields(Map commonFields) {
+ this.commonFields = commonFields;
+ for (OutputElement oe: outputsMap.values())
+ oe.setCommonFields(commonFields);
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/RefFieldElement.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/RefFieldElement.java
new file mode 100644
index 00000000..030a4a94
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/configuration/RefFieldElement.java
@@ -0,0 +1,64 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.configuration;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.CONFIGURATION.FIELDS;
+
+public class RefFieldElement extends FieldElement implements EntaxyFactory.RefFieldInfo {
+
+ protected boolean isBackRef = false;
+ protected boolean isRefByValueOnly = false;
+
+ protected String refField = FIELDS.OBJECT_ID;
+
+ /* EntaxyFactory.RefFieldInfo */
+
+ @Override
+ public boolean isBackRef() {
+ return isBackRef;
+ }
+
+ @Override
+ public boolean isRefByValueOnly() {
+ return isRefByValueOnly;
+ }
+
+ @Override
+ public String getRefField() {
+ return refField;
+ }
+
+ /* others */
+
+ public void setBackRef(boolean isBackRef) {
+ this.isBackRef = isBackRef;
+ }
+
+ public void setRefByValueOnly(boolean isRefByValueOnly) {
+ this.isRefByValueOnly = isRefByValueOnly;
+ }
+
+ public void setRefField(String refField) {
+ this.refField = refField;
+ }
+
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/impl/DefaultFactory.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/impl/DefaultFactory.java
new file mode 100644
index 00000000..9a5a6ff1
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/impl/DefaultFactory.java
@@ -0,0 +1,257 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactoryException;
+import ru.entaxy.platform.base.objects.factory.configuration.AbstractElement;
+import ru.entaxy.platform.base.objects.factory.configuration.FactoryElement;
+import ru.entaxy.platform.base.objects.factory.configuration.FieldsElement;
+import ru.entaxy.platform.base.objects.factory.configuration.OutputElement;
+import ru.entaxy.platform.base.objects.factory.configuration.OutputsElement;
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.base.support.osgi.OSGIUtils;
+
+public class DefaultFactory implements EntaxyFactory {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultFactory.class);
+
+ protected Map>> elementClasses = new HashMap<>();
+
+ protected String factoryId = "";
+
+ protected String factoryType = "";
+
+ protected String description;
+
+ protected String label;
+
+ protected String category;
+
+ protected FieldsElement fields = null;
+
+ protected OutputsElement outputs = new OutputsElement();
+
+ protected Map factoryData = new HashMap<>();
+
+ protected GenerationHelper helper = null;
+
+ public DefaultFactory() {
+ super();
+ elementClasses.put(FactoryElement.ELEMENT_NAME, FactoryElement.class);
+ elementClasses.put(OutputsElement.ELEMENT_NAME, OutputsElement.class);
+ elementClasses.put(FieldsElement.ELEMENT_NAME, FieldsElement.class);
+ }
+
+ protected GenerationHelper getHelper() {
+ if (this.helper == null) {
+ try {
+ helper = OSGIUtils.services().ofClass(GenerationHelper.class).waitService(5000).get();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ log.error("Error getting GenerationHelper", e);
+ }
+ }
+ return this.helper;
+ }
+
+ public void configure(String configuration) {
+
+ log.debug("CONFIGURE WITH: " + configuration);
+
+ GsonBuilder builder = new GsonBuilder();
+ Gson gson = builder.create();
+
+ JsonElement je = (new JsonParser()).parse(configuration);
+ JsonObject root = je.getAsJsonObject();
+
+ Set> elementSet = root.entrySet();
+ for (Entry entry: elementSet) {
+ String name = entry.getKey();
+ Object result = null;
+ if (elementClasses.containsKey(name)) {
+ log.debug("FOUND element class for [" + name + "] :: " + elementClasses.get(name));
+ try {
+ result = elementClasses.get(name).getConstructor().newInstance().fromJson(entry.getValue());
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ log.error("Error deserializing [" + name + "]", e);
+ continue;
+ }
+ // gson.fromJson(entry.getValue(), elementClasses.get(name));
+ } else
+ result = JSONUtils.element2object(entry.getValue());
+ factoryData.put(name, result);
+ postprocess(name, result);
+ }
+
+ }
+
+ protected void postprocess(String name, Object object) {
+ if (object instanceof FactoryElement) {
+ FactoryElement fe = (FactoryElement)object;
+ log.debug("POSTPROCESS :: FactoryElement");
+ if (CommonUtils.isValid(fe.getId()))
+ this.factoryId = fe.getId();
+ this.factoryType = fe.getType();
+ this.category = fe.getCategory();
+ this.label = fe.getLabel();
+ this.description = fe.getDescription();
+ } else if (object instanceof OutputsElement) {
+ log.debug("POSTPROCESS :: OutputsElement");
+ this.outputs = (OutputsElement)object;
+ log.debug("POSTPROCESS :: Default output config size -> " +
+ this.outputs.getOutput(this.outputs.getDefaultOutputType()).getConfig().size()
+ );
+ if (this.fields != null) {
+ this.outputs.setCommonFields(this.fields.getFieldsMap());
+ log.debug("COMMON FIELDS :: " + this.fields.getFieldsMap().size());
+ } else {
+ log.debug("fields :: null");
+ }
+ } else if (object instanceof FieldsElement) {
+ log.debug("POSTPROCESS :: FieldsElement");
+ this.fields = (FieldsElement)object;
+ if (this.outputs != null) {
+ this.outputs.setCommonFields(this.fields.getFieldsMap());
+ log.debug("COMMON FIELDS :: " + this.fields.getFieldsMap().size());
+ } else {
+ log.debug("outputs :: null");
+ }
+ }
+ }
+
+ public boolean isValid() {
+ return CommonUtils.isValid(this.factoryId) && CommonUtils.isValid(this.factoryType);
+ }
+
+ @Override
+ public String getId() {
+ return this.factoryId;
+ }
+
+ public void setFactoryId(String factoryId) {
+ this.factoryId = factoryId;
+ }
+
+ @Override
+ public String getType() {
+ return this.factoryType;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public String getLabel() {
+ return label;
+ }
+
+ @Override
+ public String getCategory() {
+ return category;
+ }
+
+ @Override
+ public Generated generate(Map parameters) throws EntaxyFactoryException {
+ return generate(this.outputs.getDefaultOutputType(), parameters);
+ }
+
+ @Override
+ public Generated generate(String outputType, Map parameters) throws EntaxyFactoryException {
+ if (!this.outputs.hasOutput(outputType))
+ throw new EntaxyFactoryException();
+ return this.generate(outputType, EntaxyFactory.SCOPE.PUBLIC.label, parameters);
+ }
+
+ @Override
+ public Generated generate(String outputType, String scope, Map parameters) throws EntaxyFactoryException {
+ log.debug("Generating for: output type [{}], scope [{}]", outputType, scope);
+
+ if (!this.outputs.hasOutput(outputType)) {
+ log.debug("Unknown output: {}", outputType);
+ throw new EntaxyFactoryException();
+ }
+
+ OutputElement oe = this.outputs.getOutput(outputType);
+ if (!oe.isScopeSupported(scope)) {
+ log.error("Scope not supported: {}; supported scopes: [{}]"
+ , scope
+ , oe.getSupportedScopes().stream().map(s -> s.label).collect(Collectors.joining(",")));
+ throw new EntaxyFactoryException();
+ }
+
+ if (this.getHelper() != null)
+ try {
+ return this.getHelper().generateForFactory(this, outputType, SCOPE.valueOfLabel(scope), parameters);
+ } catch (Exception e) {
+ log.error("Generate failed", e);
+ // TODO fill the exception
+ throw new EntaxyFactoryException();
+ }
+ return null;
+ }
+
+ @Override
+ public List getOutputs() {
+ return this.outputs.getOutputs().stream().map(el->(OutputInfo)el).collect(Collectors.toList());
+ }
+
+ @Override
+ public OutputInfo getOutputByType(String outputType) {
+ return this.outputs.getOutput(outputType);
+ }
+
+ @Override
+ public List getFields() {
+ return this.fields.getFields().stream().map(f -> (FieldInfo)f).collect(Collectors.toList());
+ }
+
+ @Override
+ public List getFields(String outputType) {
+ return this.outputs.getOutput(outputType).getFields();
+ }
+
+ @Override
+ public OutputInfo getDefaultOutput() {
+ return (OutputInfo)outputs.getOutput(outputs.getDefaultOutputType());
+ }
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/impl/GenerationHelper.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/impl/GenerationHelper.java
new file mode 100644
index 00000000..71aead1d
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/impl/GenerationHelper.java
@@ -0,0 +1,126 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.osgi.service.component.annotations.CollectionType;
+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 org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.base.generator.template.Template;
+import ru.entaxy.base.generator.template.TemplateService;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generator;
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.factory.GeneratorFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.OutputInfo;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.SCOPE;
+
+@Component(immediate = true, service = {GenerationHelper.class})
+public class GenerationHelper {
+
+ private static final Logger log = LoggerFactory.getLogger(GenerationHelper.class);
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY, collectionType = CollectionType.SERVICE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
+ protected volatile TemplateService templateService;
+
+ public Generated generateForFactory(EntaxyFactory factory, String outputType, SCOPE scope, Map parameters) throws Exception {
+
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "]");
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: PARAMETERS \n"
+ + parameters.entrySet().stream().map(e -> e.getKey() + ":" + (null==e.getValue()?"null":e.getValue()))
+ .collect(Collectors.toList())
+ .stream().collect(Collectors.joining(", "))
+ );
+
+ OutputInfo outputInfo = factory.getOutputByType(outputType);
+
+ if (outputInfo == null) {
+ // @TODO throw Exception
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: output [{}] not found", outputType);
+ return null;
+ }
+
+ if (!outputInfo.getScopes().contains(scope.label)) {
+ // @TODO throw Exception
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: scope [{}] not supported", scope.label);
+ return null;
+ }
+
+ // try to generate via GeneratorFactory
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: TRY via GeneratorFactory");
+ Generator g = GeneratorFactory.createGenerator(outputInfo.getGenerator(), outputInfo.getConfig());
+ if (g.isGeneratable(parameters)) {
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: generating");
+ return g.generate(parameters);
+ } else {
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: NOT generatable");
+ }
+
+ // try to generate via TemplateService
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: TRY via TemplateService");
+ List candidates = new LinkedList<>();
+ candidates.add(factory.getFactoryId() + "." + outputType + "." + scope.label);
+ candidates.add(factory.getFactoryId() + "." + outputType);
+ if (outputInfo.isDefault()) {
+ candidates.add(factory.getFactoryId() + ".default." + scope.label);
+ candidates.add(factory.getFactoryId() + ".default");
+ candidates.add(factory.getFactoryId() + "." + scope.label);
+ candidates.add(factory.getFactoryId());
+ }
+
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: CANDIDATES : ["
+ + candidates.stream().collect(Collectors.joining(";"))
+ + "]"
+ );
+
+ for (String candidate: candidates) {
+ Template t = templateService.getTemplateById(candidate);
+ if (t != null) {
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: FOUND TEMPLATE : ["
+ + candidate + "]");
+ Generated result = GeneratorFactory.createGenerator(t).generate(t, parameters);
+ return result;
+ } else {
+ log.debug("GENERATING for factory [" + factory.getFactoryId() + "] :: NOT FOUND TEMPLATE : ["
+ + candidate + "]");
+ }
+ }
+ return null;
+ }
+
+ public TemplateService getTemplateService() {
+ return templateService;
+ }
+
+ public void setTemplateService(TemplateService templateService) {
+ this.templateService = templateService;
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactory.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactory.java
new file mode 100644
index 00000000..edcfffed
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactory.java
@@ -0,0 +1,84 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.tracker;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+
+public class TrackedFactory {
+
+ private static final Logger log = LoggerFactory.getLogger(TrackedFactory.class);
+
+ public static Map trackedFactoriesMap = new HashMap<>();
+
+ private String id;
+ private Bundle bundle;
+ private String configString;
+
+ private ServiceRegistration serviceRegistration;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+ public void setBundle(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public String getConfigString() {
+ return configString;
+ }
+
+ public void setConfigString(String configString) {
+ this.configString = configString;
+ }
+
+ public ServiceRegistration getServiceRegistration() {
+ return serviceRegistration;
+ }
+
+ public void setServiceRegistration(ServiceRegistration serviceRegistration) {
+ this.serviceRegistration = serviceRegistration;
+ }
+
+ public void unregister() {
+ if (this.serviceRegistration != null)
+ try {
+ this.serviceRegistration.unregister();
+ } catch (Exception e) {
+ log.warn("TrackedFactory [" + getId() + "]", e);
+ }
+ }
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactoryCustomizer.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactoryCustomizer.java
new file mode 100644
index 00000000..e9853d31
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactoryCustomizer.java
@@ -0,0 +1,83 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.tracker;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.base.support.osgi.tracker.UniformBundleTrackerCustomizer;
+
+public class TrackedFactoryCustomizer extends UniformBundleTrackerCustomizer> {
+
+ private static final Logger log = LoggerFactory.getLogger(TrackedFactoryCustomizer.class);
+
+ private static final String FACTORY_ROOT_PATH = "/ru/entaxy/factory/";
+
+ @Override
+ protected List createManagedObject(Bundle bundle, BundleEvent event,
+ Map> filterResults) {
+
+ List result = new ArrayList<>();
+
+ Enumeration entries = bundle.findEntries(FACTORY_ROOT_PATH, "*.json", false);
+ while (entries.hasMoreElements()) {
+ URL entry = entries.nextElement();
+ String urlString = entry.toString();
+ log.debug("Found path: " + urlString);
+ if (urlString.endsWith("/"))
+ continue;
+ String id = urlString.substring(urlString.lastIndexOf("/") + 1);
+ id = id.substring(0, id.lastIndexOf("."));
+ log.debug("Found id: " + id);
+
+ try {
+ String config = new BufferedReader (
+ new InputStreamReader(
+ entry.openStream(), StandardCharsets.UTF_8))
+ .lines()
+ .collect(Collectors.joining("\n"));
+ TrackedFactory tf = new TrackedFactory();
+ tf.setId(id);
+ tf.setBundle(bundle);
+ tf.setConfigString(config);
+ result.add(tf);
+ } catch (Exception e) {
+ log.error("Error reading url: " + urlString, e);
+ }
+ }
+
+ return result;
+ }
+
+
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactoryCustomizerListener.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactoryCustomizerListener.java
new file mode 100644
index 00000000..d0f63e65
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackedFactoryCustomizerListener.java
@@ -0,0 +1,102 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.tracker;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.base.generator.template.TemplateService;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.objects.factory.impl.DefaultFactory;
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.osgi.tracker.BundleTrackerCustomizerListener;
+
+public class TrackedFactoryCustomizerListener implements BundleTrackerCustomizerListener> {
+
+ private static final Logger log = LoggerFactory.getLogger(TrackedFactoryCustomizerListener.class);
+
+ protected BundleContext bundleContext;
+
+ public TrackedFactoryCustomizerListener(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public void added(List managedObject) {
+ if (managedObject == null) {
+ log.debug("managedObject is null");
+ return;
+ }
+ for (TrackedFactory tf: managedObject) {
+ log.debug("Added factory: " + tf.getId());
+ if (TrackedFactory.trackedFactoriesMap.containsKey(tf.getId())) {
+ TrackedFactory.trackedFactoriesMap.get(tf.getId()).unregister();
+ }
+ DefaultFactory defaultFactory = new DefaultFactory();
+ defaultFactory.setFactoryId(tf.getId());
+ defaultFactory.configure(tf.getConfigString());
+ if (defaultFactory.isValid()) {
+
+ tf.setId(defaultFactory.getFactoryId());
+
+ Dictionary props = new Hashtable();
+ props.put(EntaxyFactory.SERVICE.PROP_ID, defaultFactory.getFactoryId());
+ props.put(EntaxyFactory.SERVICE.PROP_TYPE, defaultFactory.getFactoryType());
+ props.put(EntaxyFactory.SERVICE.PROP_ORIGIN_BUNDLE, tf.getBundle().getBundleId()+"");
+
+ tf.setServiceRegistration(
+ this.bundleContext.registerService(EntaxyFactory.class, defaultFactory, props)
+ );
+
+ TrackedFactory.trackedFactoriesMap.put(tf.getId(), tf);
+ }
+ }
+ }
+
+ @Override
+ public void modified(List managedObject) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void removed(List managedObject) {
+ if (managedObject == null)
+ return;
+ for (TrackedFactory tf: managedObject) {
+ try {
+ tf.getServiceRegistration().unregister();
+ } catch (Exception e) {
+ // do nothing
+ }
+ TrackedFactory.trackedFactoriesMap.remove(tf.getId());
+ }
+
+ }
+
+
+
+}
diff --git a/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackerManager.java b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackerManager.java
new file mode 100644
index 00000000..19189bb8
--- /dev/null
+++ b/platform/runtime/base/objects-base/object-factory/src/main/java/ru/entaxy/platform/base/objects/factory/tracker/TrackerManager.java
@@ -0,0 +1,69 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.factory.tracker;
+
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.util.tracker.BundleTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.base.support.osgi.tracker.BundleTrackerUtils;
+import ru.entaxy.platform.base.support.osgi.tracker.filter.BundleHeaderFilter;
+
+@Component(service = {TrackerManager.class}, immediate = true)
+public class TrackerManager {
+
+ private static final Logger log = LoggerFactory.getLogger(TrackerManager.class);
+
+ protected BundleContext bundleContext;
+
+ protected BundleTracker> factoryTracker;
+
+ @Activate
+ public void activate(ComponentContext componentContext) {
+ this.bundleContext = componentContext.getBundleContext();
+ log.debug("Activated: " + bundleContext.getBundle().getBundleId());
+
+ factoryTracker = BundleTrackerUtils.>createBuilder()
+ .addFilter(
+ (new BundleHeaderFilter()).header("Entaxy-Factory-Provider")
+ )
+ .customizer(
+ (new TrackedFactoryCustomizer())
+ .listener(new TrackedFactoryCustomizerListener(bundleContext))
+ )
+ .bundleState(Bundle.ACTIVE | Bundle.INSTALLED | Bundle.RESOLVED)
+ .get();
+ factoryTracker.open();
+ log.debug("Factory tracker started");
+ }
+
+ @Deactivate
+ public void deactivate(ComponentContext componentContext) {
+ factoryTracker.close();
+ }
+}
diff --git a/platform/runtime/base/objects-base/objects-core/LICENSE.txt b/platform/runtime/base/objects-base/objects-core/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/base/objects-base/objects-core/pom.xml b/platform/runtime/base/objects-base/objects-core/pom.xml
new file mode 100644
index 00000000..22450753
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/pom.xml
@@ -0,0 +1,38 @@
+
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime.base
+ objects-base
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.base.objects-base
+ objects-core
+ bundle
+ ENTAXY :: PLATFORM :: BASE :: OBJECTS BASE :: OBJECTS CORE
+ ENTAXY :: PLATFORM :: BASE :: OBJECTS BASE :: OBJECTS CORE
+
+
+
+ ru.entaxy.platform.base.objects,
+ ru.entaxy.platform.base.objects.service.impl,
+ ru.entaxy.platform.base.objects.service.tracker,
+ ru.entaxy.platform.base.objects.shell,
+ ru.entaxy.platform.base.objects.shell.completers,
+ ru.entaxy.platform.base.objects.storage.impl
+
+ none
+
+
+
+
+ ru.entaxy.esb.platform.runtime.base
+ base-support
+ ${project.version}
+
+
+ org.apache.karaf.shell
+ org.apache.karaf.shell.core
+ ${karaf.version}
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObject.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObject.java
new file mode 100644
index 00000000..18c7d0aa
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObject.java
@@ -0,0 +1,86 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects;
+
+public interface EntaxyObject {
+
+ public interface HEADERS {
+
+ String MAIN_OBJECT = "Entaxy-Main-Object";
+ String GENERATED_OBJECTS = "Entaxy-Generated-Object";
+ // public static final String HEADER_MAIN_OBJECT_ID = "Entaxy-Main-Object-Id";
+ // public static final String HEADER_MAIN_OBJECT_TYPE = "Entaxy-Main-Object-Type";
+ // public static final String HEADER_MAIN_OBJECT_FACTORY_ID = "Entaxy-Main-Object-Factory";
+ // public static final String HEADER_OBJECT_ID = "Entaxy-Generated-Object";
+ // public static final String HEADER_OBJECT_TYPE = "Entaxy-Generated-Object-Type";
+ String GENERATED_OBJECTS_CONFIG = "Entaxy-Generated-Object-Configuration";
+
+ }
+
+ public interface FIELDS {
+
+ public static final String FACTORY_ID = "factoryId";
+ public static final String SCOPE = "scope";
+
+ public static final String OBJECT_ID = "objectId";
+ public static final String OBJECT_TYPE = "type";
+
+ public static final String IS_REF = "isRef";
+ public static final String IS_BACK_REF = "isBackRef";
+ public static final String IS_REF_BY_VALUE_ONLY = "isRefByValueOnly";
+ public static final String REF_FIELD = "refField";
+
+ public static final String DEFAULT_VALUE = "defaultValue";
+
+ public static final String PROPERTIES = "properties";
+
+ public static final String FIELDS_TO_PUBLISH = "##publish";
+ }
+
+ public interface OBJECT_TYPES {
+
+ public static final String ENTAXY_RUNTIME_TYPE_PREFIX = "entaxy.runtime.";
+
+ public static final String PROFILE = ENTAXY_RUNTIME_TYPE_PREFIX + "profile";
+ public static final String CONNECTOR = ENTAXY_RUNTIME_TYPE_PREFIX + "connector";
+ public static final String CONNECTION = ENTAXY_RUNTIME_TYPE_PREFIX + "connection";
+ public static final String DEFAULT_ROUTE = ENTAXY_RUNTIME_TYPE_PREFIX + "default-route";
+
+ public static boolean isRuntimeType(String typeName) {
+ return (typeName!=null) && typeName.startsWith(ENTAXY_RUNTIME_TYPE_PREFIX);
+ }
+
+ }
+
+ public static interface BundleInfo {
+ public long getBundleId();
+ }
+
+ public String getObjectId();
+ public String getObjectType();
+ public default String getObjectFullId() {
+ return getObjectId() + ":" + getObjectType();
+ };
+
+ public String getFactoryId();
+ public BundleInfo getBundleInfo();
+ public String getConfiguration();
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectService.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectService.java
new file mode 100644
index 00000000..1c660e82
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectService.java
@@ -0,0 +1,28 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects;
+
+import java.util.List;
+
+public interface EntaxyObjectService {
+
+ public List getObjects();
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectStorage.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectStorage.java
new file mode 100644
index 00000000..d510b9d8
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectStorage.java
@@ -0,0 +1,29 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects;
+
+import java.util.Map;
+
+public interface EntaxyObjectStorage {
+
+ public String[] getObjectTypes();
+ public Object store(Map data);
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectStorageService.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectStorageService.java
new file mode 100644
index 00000000..2d265469
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/EntaxyObjectStorageService.java
@@ -0,0 +1,26 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects;
+
+public interface EntaxyObjectStorageService {
+
+ public EntaxyObjectStorage getObjectStorage(String objectType);
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/BundleInfoImpl.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/BundleInfoImpl.java
new file mode 100644
index 00000000..0ead5956
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/BundleInfoImpl.java
@@ -0,0 +1,42 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.service.impl;
+
+import org.osgi.framework.BundleContext;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+
+public class BundleInfoImpl implements EntaxyObject.BundleInfo {
+
+ protected BundleContext bundleContext;
+ protected long bundleId;
+
+ public BundleInfoImpl(BundleContext bundleContext, long trackedBundleId) {
+ super();
+ this.bundleContext = bundleContext;
+ this.bundleId = trackedBundleId;
+ }
+
+ @Override
+ public long getBundleId() {
+ return this.bundleId;
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/EntaxyObjectServiceImpl.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/EntaxyObjectServiceImpl.java
new file mode 100644
index 00000000..80957405
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/EntaxyObjectServiceImpl.java
@@ -0,0 +1,100 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.service.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.util.tracker.BundleTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.EntaxyObjectService;
+import ru.entaxy.platform.base.objects.service.tracker.TrackedEntaxyObjectCustomizer;
+import ru.entaxy.platform.base.objects.service.tracker.TrackedEntaxyObjectCustomizerListener;
+import ru.entaxy.platform.base.support.osgi.tracker.BundleTrackerUtils;
+import ru.entaxy.platform.base.support.osgi.tracker.filter.BundleHeaderFilter;
+
+@Component(service = {EntaxyObjectService.class}, immediate = true)
+public class EntaxyObjectServiceImpl implements EntaxyObjectService {
+
+ private static final Logger log = LoggerFactory.getLogger(EntaxyObjectServiceImpl.class);
+
+ protected BundleContext bundleContext;
+
+ protected BundleTracker> objectTracker;
+
+ protected Map trackedObjects = new HashMap<>();
+
+ @Activate
+ public void activate(ComponentContext componentContext) {
+ this.bundleContext = componentContext.getBundleContext();
+ openTracker();
+ }
+
+ @Deactivate
+ public void deactivate(ComponentContext componentContext) {
+ this.objectTracker.close();
+ }
+
+
+ @Override
+ public List getObjects() {
+ return trackedObjects.values().stream().collect(Collectors.toList());
+ }
+
+ protected void openTracker() {
+ objectTracker = BundleTrackerUtils.>createBuilder()
+ .addFilter(
+ (new BundleHeaderFilter()).header(EntaxyObject.HEADERS.GENERATED_OBJECTS)
+ )
+ .customizer(
+ (new TrackedEntaxyObjectCustomizer(this))
+ .listener(new TrackedEntaxyObjectCustomizerListener(this))
+ )
+ .bundleState(Bundle.ACTIVE | Bundle.INSTALLED | Bundle.RESOLVED)
+ .get();
+ objectTracker.open();
+ }
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void addObjects(List objects) {
+ for (TrackedEntaxyObject object: objects)
+ this.trackedObjects.put(object.getObjectId() + ":" + object.getObjectType(), object);
+ }
+
+ public void removeObjects(List objects) {
+ for (TrackedEntaxyObject object: objects)
+ this.trackedObjects.remove(object.getObjectId() + ":" + object.getObjectType());
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/TrackedEntaxyObject.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/TrackedEntaxyObject.java
new file mode 100644
index 00000000..fb563ab1
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/impl/TrackedEntaxyObject.java
@@ -0,0 +1,99 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.service.impl;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.support.JSONUtils;
+
+public class TrackedEntaxyObject implements EntaxyObject {
+
+ static public TrackedEntaxyObject create(BundleContext bundleContext, String objectId, String objectType) {
+ return new TrackedEntaxyObject(bundleContext, objectId, objectType);
+ }
+
+ protected BundleContext bundleContext;
+
+ protected String objectId;
+ protected String objectType;
+ protected String factoryId = "UNKNOWN";
+
+ protected JsonObject configuration;
+
+ protected BundleInfoImpl bundleInfoImpl;
+
+ protected TrackedEntaxyObject(BundleContext bundleContext, String objectId, String objectType) {
+ super();
+ this.bundleContext = bundleContext;
+ this.objectId = objectId;
+ this.objectType = objectType;
+ }
+
+ @Override
+ public String getObjectId() {
+ return this.objectId;
+ }
+
+ @Override
+ public String getObjectType() {
+ return this.objectType;
+ }
+
+ @Override
+ public String getFactoryId() {
+ return this.factoryId;
+ }
+
+ @Override
+ public BundleInfo getBundleInfo() {
+ return this.bundleInfoImpl;
+ }
+
+ @Override
+ public String getConfiguration() {
+ return (this.configuration == null?"{}":this.configuration.toString());
+ }
+
+ public TrackedEntaxyObject bundle(Bundle bundleValue) {
+ this.bundleInfoImpl = new BundleInfoImpl(bundleContext, bundleValue.getBundleId());
+ return this;
+ };
+
+ public TrackedEntaxyObject configuration(String configurationValue) {
+
+ try {
+ this.configuration = JSONUtils.getJsonRootObject(configurationValue);
+ if (this.configuration.has(EntaxyObject.FIELDS.FACTORY_ID))
+ this.factoryId = this.configuration.get(EntaxyObject.FIELDS.FACTORY_ID).getAsString();
+ } catch (Exception e) {
+
+ }
+
+ if (this.configuration == null)
+ this.configuration = new JsonObject();
+
+ return this;
+ };
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/tracker/TrackedEntaxyObjectCustomizer.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/tracker/TrackedEntaxyObjectCustomizer.java
new file mode 100644
index 00000000..7dc00167
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/service/tracker/TrackedEntaxyObjectCustomizer.java
@@ -0,0 +1,76 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.service.tracker;
+
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.service.impl.EntaxyObjectServiceImpl;
+import ru.entaxy.platform.base.objects.service.impl.TrackedEntaxyObject;
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.osgi.tracker.UniformBundleTrackerCustomizer;
+
+public class TrackedEntaxyObjectCustomizer extends UniformBundleTrackerCustomizer> {
+
+ protected EntaxyObjectServiceImpl objectServiceImpl;
+
+ public TrackedEntaxyObjectCustomizer(EntaxyObjectServiceImpl objectServiceImpl) {
+ super();
+ this.objectServiceImpl = objectServiceImpl;
+ }
+
+ @Override
+ protected List createManagedObject(Bundle bundle, BundleEvent event,
+ Map> filterResults) {
+
+ List result = new ArrayList<>();
+
+ String objectsHeader = bundle.getHeaders().get(EntaxyObject.HEADERS.GENERATED_OBJECTS);
+ String configHeader = bundle.getHeaders().get(EntaxyObject.HEADERS.GENERATED_OBJECTS_CONFIG);
+
+ String[] objects = objectsHeader.split(",");
+ String[] configs = configHeader.split(",");
+
+ for (int i=0; i> {
+
+ protected EntaxyObjectServiceImpl objectServiceImpl;
+
+ public TrackedEntaxyObjectCustomizerListener(EntaxyObjectServiceImpl objectServiceImpl) {
+ super();
+ this.objectServiceImpl = objectServiceImpl;
+ }
+
+
+ @Override
+ public void added(List managedObject) {
+ this.objectServiceImpl.addObjects(managedObject);
+ }
+
+ @Override
+ public void modified(List managedObject) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void removed(List managedObject) {
+ this.objectServiceImpl.removeObjects(managedObject);
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/EntaxyObjectServiceSupport.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/EntaxyObjectServiceSupport.java
new file mode 100644
index 00000000..8dc8f45e
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/EntaxyObjectServiceSupport.java
@@ -0,0 +1,33 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.shell;
+
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+import ru.entaxy.platform.base.objects.EntaxyObjectService;
+
+public class EntaxyObjectServiceSupport {
+
+ public static final String OBJECTS_SCOPE = "objects";
+
+ @Reference
+ EntaxyObjectService objectService;
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ListObjects.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ListObjects.java
new file mode 100644
index 00000000..50f8c21a
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ListObjects.java
@@ -0,0 +1,57 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.shell;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+
+@Service
+@Command(name = "object-list", scope = EntaxyObjectServiceSupport.OBJECTS_SCOPE)
+public class ListObjects extends EntaxyObjectServiceSupport implements Action {
+
+ @Override
+ public Object execute() throws Exception {
+
+ ShellTable shellTable = new ShellTable();
+ shellTable.column("Id");
+ shellTable.column("Type");
+ shellTable.column("Full Id");
+ shellTable.column("Factory Id");
+ shellTable.column("Bundle Id");
+
+ for (EntaxyObject object: objectService.getObjects())
+ shellTable.addRow().addContent(
+ object.getObjectId(),
+ object.getObjectType(),
+ object.getObjectFullId(),
+ object.getFactoryId(),
+ object.getBundleInfo().getBundleId()
+ );
+
+ shellTable.print(System.out);
+
+ return null;
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ObjectAwareCommand.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ObjectAwareCommand.java
new file mode 100644
index 00000000..bc3dbdcd
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ObjectAwareCommand.java
@@ -0,0 +1,56 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.shell;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Completion;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.shell.completers.ObjectCompleter;
+
+public abstract class ObjectAwareCommand extends EntaxyObjectServiceSupport implements Action {
+
+ @Argument (index = 0, name = "objectFullId", required = true)
+ @Completion(caseSensitive = false, value = ObjectCompleter.class)
+ String objectFullId;
+
+ EntaxyObject entaxyObject;
+
+ @Override
+ public Object execute() throws Exception {
+
+ List candidates = objectService.getObjects()
+ .stream().filter(obj->obj.getObjectFullId().equals(objectFullId))
+ .collect(Collectors.toList());
+ if (candidates.size()>0) {
+ entaxyObject = candidates.get(0);
+ return doExecute();
+ } else {
+ throw new IllegalArgumentException("Object not found by full Id: [" + objectFullId + "]");
+ }
+ }
+
+ public abstract Object doExecute() throws Exception;
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ObjectConfiguration.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ObjectConfiguration.java
new file mode 100644
index 00000000..a88b909b
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/ObjectConfiguration.java
@@ -0,0 +1,35 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.shell;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Service
+@Command(name = "object-config", scope = EntaxyObjectServiceSupport.OBJECTS_SCOPE)
+public class ObjectConfiguration extends ObjectAwareCommand {
+
+ @Override
+ public Object doExecute() throws Exception {
+ System.out.println(entaxyObject.getConfiguration());
+ return null;
+ }
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/completers/ObjectCompleter.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/completers/ObjectCompleter.java
new file mode 100644
index 00000000..f1741bb9
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/shell/completers/ObjectCompleter.java
@@ -0,0 +1,51 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.shell.completers;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+import ru.entaxy.platform.base.objects.EntaxyObjectService;
+
+@Service
+public class ObjectCompleter implements Completer {
+
+ @Reference
+ EntaxyObjectService objectService;
+
+ @Override
+ public int complete(Session session, CommandLine commandLine, List candidates) {
+ candidates.addAll(
+ objectService.getObjects().stream()
+ .map(obj->obj.getObjectFullId())
+ .collect(Collectors.toList())
+ );
+ return 0;
+ }
+
+
+
+}
diff --git a/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/storage/impl/EntaxyObjectStorageServiceImpl.java b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/storage/impl/EntaxyObjectStorageServiceImpl.java
new file mode 100644
index 00000000..8c22d580
--- /dev/null
+++ b/platform/runtime/base/objects-base/objects-core/src/main/java/ru/entaxy/platform/base/objects/storage/impl/EntaxyObjectStorageServiceImpl.java
@@ -0,0 +1,63 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.base.objects.storage.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.component.annotations.CollectionType;
+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 org.osgi.service.component.annotations.ReferencePolicyOption;
+
+import ru.entaxy.platform.base.objects.EntaxyObjectStorage;
+import ru.entaxy.platform.base.objects.EntaxyObjectStorageService;
+
+@Component(service = EntaxyObjectStorageService.class, immediate = true)
+public class EntaxyObjectStorageServiceImpl implements EntaxyObjectStorageService {
+
+ protected Map objectStorages = new HashMap<>();
+
+ @Override
+ public EntaxyObjectStorage getObjectStorage(String objectType) {
+ return this.objectStorages.get(objectType);
+ }
+
+ @Reference(bind = "addObjectStorage", unbind = "removeObjectStorage", cardinality = ReferenceCardinality.MULTIPLE
+ , policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, collectionType = CollectionType.SERVICE)
+ public void addObjectStorage(EntaxyObjectStorage objectStorage) {
+ String[] types = objectStorage.getObjectTypes();
+ if (types == null)
+ return;
+ for (int i=0; i
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime
+ base
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.base
+ objects-base
+ pom
+ ENTAXY :: PLATFORM :: BASE :: OBJECT-FACTORING
+ ENTAXY :: PLATFORM :: BASE :: OBJECT-FACTORING
+
+
+ com.google.code.gson
+ gson
+
+
+ org.osgi
+ org.osgi.service.component.annotations
+
+
+ org.apache.felix
+ org.apache.felix.scr
+
+
+
+ objects-core
+ object-factory
+
+
\ No newline at end of file
diff --git a/platform/runtime/base/pom.xml b/platform/runtime/base/pom.xml
index 7f3aa562..73ecfc90 100644
--- a/platform/runtime/base/pom.xml
+++ b/platform/runtime/base/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform
runtime
- 1.8.1
+ 1.8.2
4.0.0
@@ -16,10 +16,23 @@
Entaxy Platform runtime base
pom
+
+
+ org.osgi
+ org.osgi.service.component.annotations
+
+
+ org.apache.felix
+ org.apache.felix.scr
+
+
+
base-support
branding
connecting
management-core
+ objects-base
+ config-extensions
\ No newline at end of file
diff --git a/platform/runtime/base/src/main/features/features.xml b/platform/runtime/base/src/main/features/features.xml
index 88b90c2c..7e944dd4 100644
--- a/platform/runtime/base/src/main/features/features.xml
+++ b/platform/runtime/base/src/main/features/features.xml
@@ -32,15 +32,17 @@
mvn:ru.entaxy.esb.system/system-parent/${project.version}/xml/features
- mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.freemarker/2.3.29_1
-
+ mvn:org.freemarker/freemarker/${freemarker.version}
+
entaxy-freemarker-support
entaxy-legacy-system
- mvn:ru.entaxy.esb.platform.runtime.base/base-support/${project.version}
+ base-support
+ extensions
entaxy-branding
management-core
+ objects-base
connecting
@@ -50,10 +52,26 @@
+
+ mvn:ru.entaxy.esb.platform.runtime.base/base-support/${project.version}
+
+
+
+ base-support
+ mvn:ru.entaxy.esb.platform.runtime.base/config-extensions/${project.version}
+
+
+
mvn:ru.entaxy.esb.platform.runtime.base/management-core/${project.version}
+
+ generator
+ mvn:ru.entaxy.esb.platform.runtime.base.objects-base/objects-core/${project.version}
+ mvn:ru.entaxy.esb.platform.runtime.base.objects-base/object-factory/${project.version}
+
+
generator
@@ -63,8 +81,10 @@
+ base-support
mvn:ru.entaxy.esb.platform.runtime.base.connecting.generator/generator-api/${project.version}
mvn:ru.entaxy.esb.platform.runtime.base.connecting.generator/generator-factory/${project.version}
+ mvn:ru.entaxy.esb.platform.runtime.base.connecting.generator/template-service-shell/${project.version}
mvn:ru.entaxy.esb.platform.runtime.base.connecting.generator/ftl-generator/${project.version}
mvn:ru.entaxy.esb.platform.runtime.base.connecting.generator/common-templates-collection/${project.version}
diff --git a/platform/runtime/core/artifact-management/pom.xml b/platform/runtime/core/artifact-management/pom.xml
index 3298e33c..14f98132 100644
--- a/platform/runtime/core/artifact-management/pom.xml
+++ b/platform/runtime/core/artifact-management/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime
core
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core
artifact-management
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifact.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifact.java
index a021263f..5c260f81 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifact.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifact.java
@@ -22,6 +22,8 @@ package ru.entaxy.platform.core.artifact;
import java.io.File;
import java.util.Map;
+import ru.entaxy.platform.core.artifact.capabilities.CapabilityDescriptor;
+
public interface Artifact {
public static final String ARTIFACT_CATEGORY_UNKNOWN = "unknown";
@@ -35,9 +37,6 @@ public interface Artifact {
public static final String DEFAULT_RUNTIME_GROUP_ID = "entaxy.runtime";
- public static final String MANIFEST_HEADER_ENTAXY_BUNLDE = "Entaxy-Bundle";
- public static final String MANIFEST_HEADER_ENTAXY_RUNTIME = "Entaxy-Runtime";
-
public String getCategory();
public ArtifactCoordinates getCoordinates();
@@ -55,7 +54,13 @@ public interface Artifact {
// capabilities support
+ @Deprecated(forRemoval = true, since = "1.8.2")
public CapabilityDescriptor provideCapability(String namespace);
+ @Deprecated(forRemoval = true, since = "1.8.2")
public CapabilityDescriptor requireCapability(String namespace);
+
+ public default boolean isManifested() {
+ return Manifested.class.isAssignableFrom(this.getClass());
+ }
}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactCoordinates.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactCoordinates.java
index 78ecef8e..21b245b9 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactCoordinates.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactCoordinates.java
@@ -19,7 +19,10 @@
*/
package ru.entaxy.platform.core.artifact;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Set;
import org.apache.camel.tooling.model.Strings;
@@ -29,14 +32,47 @@ public class ArtifactCoordinates {
public static final ArtifactCoordinates EMPTY = new ArtifactCoordinates();
+ public static final String DEFAULT_VERSION = "1.0.0";
+
+ public static final String SNAPSHOT_QUALIFIER = "SNAPSHOT";
+
+ // x.y.z[-qualifier]
+ public static final String VERSION_POLICY_CLEAR = "";
+ // x.y.z-timestamp
+ public static final String VERSION_POLICY_TIMESTAMPED = "timestamped";
+ // x.y.z-yyMMddHHmmss
+ public static final String VERSION_POLICY_DATED = "dated";
+ // x.yyMMdd.HHmmss[-qualifier]
+ public static final String VERSION_POLICY_DATED_EMBEDDED = "dated-embedded";
+
protected String groupId;
protected String artifactId;
protected String version = "1.0";
protected String type;
protected String classifier;
+ protected String versionPolicy = VERSION_POLICY_CLEAR;
+
protected String versionQualifier = "";
+ protected String timestamp = "";
+
+ protected Calendar calendar = null;
+
+ protected boolean isSnapshot = false;
+
+ protected Set allowedPolicies = new HashSet<>() {/**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ {
+ add(VERSION_POLICY_CLEAR);
+ add(VERSION_POLICY_DATED);
+ add(VERSION_POLICY_DATED_EMBEDDED);
+ add(VERSION_POLICY_TIMESTAMPED);
+ }};
+
public ArtifactCoordinates groupId(String groupId) {
setGroupId(groupId);
return this;
@@ -47,6 +83,12 @@ public class ArtifactCoordinates {
return this;
}
+ public ArtifactCoordinates versionPolicy(String versionPolicy) {
+ if (this.allowedPolicies.contains(versionPolicy))
+ this.versionPolicy = versionPolicy;
+ return this;
+ }
+
public ArtifactCoordinates version(String version) {
this.versionQualifier = "";
setVersion(version);
@@ -54,20 +96,95 @@ public class ArtifactCoordinates {
}
public ArtifactCoordinates timestampedVersion(String version) {
- version(version);
- this.versionQualifier = "-" + Calendar.getInstance().getTimeInMillis();
+ this.version(version);
+ this.timestamped();
+ // versionQualifier = "-" + Calendar.getInstance().getTimeInMillis();
+ return this;
+ }
+
+ public ArtifactCoordinates timestamp(String timestamp) {
+ this.timestamp = timestamp;
return this;
}
public ArtifactCoordinates timestamped() {
- return qualifier(Calendar.getInstance().getTimeInMillis()+"");
+ return timestamped(Calendar.getInstance().getTimeInMillis()+"");
}
public ArtifactCoordinates timestamped(String timestamp) {
- if (CommonUtils.isValid(timestamp))
- return qualifier(timestamp);
- else
- return timestamped();
+ if (CommonUtils.isValid(timestamp)) {
+ this.timestamp = timestamp;
+ this.versionPolicy(VERSION_POLICY_TIMESTAMPED);
+ } else {
+ this.timestamp = "";
+ this.versionPolicy(VERSION_POLICY_CLEAR);
+ }
+ return this;
+ }
+
+ public ArtifactCoordinates datedVersion(String version) {
+ this.version(version);
+ this.dated();
+ // versionQualifier = "-" + Calendar.getInstance().getTimeInMillis();
+ return this;
+ }
+
+ public ArtifactCoordinates dated() {
+ this.calendar = Calendar.getInstance();
+ versionPolicy(VERSION_POLICY_DATED);
+ return this;
+ }
+
+ public ArtifactCoordinates datedEmbeddedVersion(String version) {
+ this.version(version);
+ this.datedEmbedded();
+ return this;
+ }
+
+ public ArtifactCoordinates datedEmbedded() {
+ this.calendar = Calendar.getInstance();
+ versionPolicy(VERSION_POLICY_DATED_EMBEDDED);
+ return this;
+ }
+
+ protected String getResultQualifier() {
+ if (isSnapshot)
+ return "-" + SNAPSHOT_QUALIFIER;
+ if (CommonUtils.isValid(this.versionQualifier))
+ return "-" + this.versionQualifier;
+ return "";
+ }
+
+ protected String calculateFinalVersion() {
+ if (VERSION_POLICY_TIMESTAMPED.equals(this.versionPolicy)) {
+ if (!CommonUtils.isValid(this.timestamp))
+ this.timestamp = Calendar.getInstance().getTimeInMillis() + "";
+ return this.version + "-" + this.timestamp;
+ }
+ if (VERSION_POLICY_DATED.equals(this.versionPolicy)) {
+ prepareCalendar();
+ return this.version + "-" + ((new SimpleDateFormat("yyMMddHHmmss")).format(this.calendar.getTime()));
+ }
+ if (VERSION_POLICY_DATED_EMBEDDED.equals(this.versionPolicy)) {
+ prepareCalendar();
+ return this.version.split("\\.")[0]
+ + "."
+ + ((new SimpleDateFormat("yyMMdd.HHmmss")).format(this.calendar.getTime()))
+ + getResultQualifier();
+ }
+ return this.version + this.getResultQualifier();
+ }
+
+ protected void prepareCalendar() {
+ if (this.calendar == null)
+ this.calendar = Calendar.getInstance();
+ if (CommonUtils.isValid(this.timestamp)) {
+ try {
+ this.calendar.setTimeInMillis(Long.parseLong(this.timestamp));
+ } catch (Exception e) {
+ // NOOP
+ }
+ }
}
public ArtifactCoordinates type(String type) {
@@ -77,7 +194,7 @@ public class ArtifactCoordinates {
public ArtifactCoordinates qualifier(String qualifier) {
if (CommonUtils.isValid(qualifier))
- this.versionQualifier = "-" + qualifier;
+ this.versionQualifier = qualifier;
else
this.versionQualifier = "";
return this;
@@ -112,10 +229,13 @@ public class ArtifactCoordinates {
}
public boolean isSnapshot() {
- return !Strings.isNullOrEmpty(this.version)
- && this.version.endsWith("-SNAPSHOT");
+ return this.isSnapshot || SNAPSHOT_QUALIFIER.equals(this.versionQualifier);
}
+ public void setSnapshot(boolean isSnapshot) {
+ this.isSnapshot = isSnapshot;
+ }
+
public String getGroupId() {
return groupId;
}
@@ -129,18 +249,26 @@ public class ArtifactCoordinates {
this.artifactId = artifactId;
}
public String getVersion() {
- return version + versionQualifier;
+ return this.calculateFinalVersion();
}
public void setVersion(String version) {
if (!CommonUtils.isValid(version))
- this.version = "1.0.0";
+ this.version = DEFAULT_VERSION;
else {
String[] splitted = version.split("\\.");
- if (splitted.length == 2)
- this.version = version + ".0";
- else if ((splitted.length==3) && (!CommonUtils.isValid(splitted[2])))
- this.version = version + "0";
- else this.version = version;
+ String[] splittedDefault = DEFAULT_VERSION.split("\\.");
+
+ String result = "";
+ for (int i=0; i= i+1) && CommonUtils.isValid(splitted[i]))
+ result += splitted[i];
+ else
+ result += splittedDefault[i];
+ }
+
+ this.version = result;
}
}
public String getType() {
@@ -156,9 +284,17 @@ public class ArtifactCoordinates {
this.classifier = classifier;
}
+ public String getVersionPolicy() {
+ return versionPolicy;
+ }
+
+ public void setVersionPolicy(String versionPolicy) {
+ this.versionPolicy(versionPolicy);
+ }
+
@Override
public String toString() {
- String result = String.format("%s/%s/%s%s", groupId, artifactId, version, versionQualifier);
+ String result = String.format("%s/%s/%s", getGroupId(), getArtifactId(), getVersion());
if (!Strings.isNullOrEmpty(type)) {
result += "/" + type;
if (!Strings.isNullOrEmpty(classifier))
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/CapabilityDescriptor.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactManifest.java
similarity index 65%
rename from platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/CapabilityDescriptor.java
rename to platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactManifest.java
index 53981362..4b7a27eb 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/CapabilityDescriptor.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/ArtifactManifest.java
@@ -1,8 +1,8 @@
/*-
* ~~~~~~licensing~~~~~~
- * artifact-management
+ * test-producers
* ==========
- * Copyright (C) 2020 - 2021 EmDev LLC
+ * Copyright (C) 2020 - 2022 EmDev LLC
* ==========
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,12 +19,17 @@
*/
package ru.entaxy.platform.core.artifact;
-import org.osgi.resource.Capability;
+import java.util.Map;
-public interface CapabilityDescriptor extends Capability {
+public interface ArtifactManifest {
- public CapabilityDescriptor namespace(String namespace);
- public CapabilityDescriptor attribute(String name, String value);
- public CapabilityDescriptor attribute(String name, String value, String type);
+ public static interface HEADERS {
+
+ String ENTAXY_BUNDLE = "Entaxy-Bundle";
+ String ENTAXY_RUNTIME = "Entaxy-Runtime";
+
+ }
+
+ public Map getCustomAttributes();
}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifacts.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifacts.java
index c129bc00..127ba36e 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifacts.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Artifacts.java
@@ -57,17 +57,17 @@ public class Artifacts {
if (DefaultArtifact.class.isAssignableFrom(instance.getClass()))
return (DefaultArtifact)instance;
} catch (NoSuchMethodException e) {
- log.error("Erorr creating artifact", e);
+ log.error("Error creating artifact", e);
} catch (SecurityException e) {
- log.error("Erorr creating artifact", e);
+ log.error("Error creating artifact", e);
} catch (InstantiationException e) {
- log.error("Erorr creating artifact", e);
+ log.error("Error creating artifact", e);
} catch (IllegalAccessException e) {
- log.error("Erorr creating artifact", e);
+ log.error("Error creating artifact", e);
} catch (IllegalArgumentException e) {
- log.error("Erorr creating artifact", e);
+ log.error("Error creating artifact", e);
} catch (InvocationTargetException e) {
- log.error("Erorr creating artifact", e);
+ log.error("Error creating artifact", e);
}
}
return new DefaultArtifact();
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Blueprint.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Blueprint.java
index 0d2ea08b..f16b4b80 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Blueprint.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Blueprint.java
@@ -19,23 +19,13 @@
*/
package ru.entaxy.platform.core.artifact;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.jar.Manifest;
-import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import ru.entaxy.platform.base.support.CommonUtils;
import ru.entaxy.platform.base.support.xml.CommonXMLUtils;
import ru.entaxy.platform.core.artifact.annotation.ArtifactSupport;
@@ -43,10 +33,14 @@ import ru.entaxy.platform.core.artifact.annotation.ArtifactSupport;
, supportedContentClasses = {String.class, Document.class, byte[].class}
, defaultArtifactClassifier = Artifact.ARTIFACT_CATEGORY_BLUEPRINT
, defaultArtifactType = "xml")
-public class Blueprint extends DefaultArtifact {
+public class Blueprint extends DefaultArtifact implements Manifested {
private final static Logger log = LoggerFactory.getLogger(Blueprint.class);
+ public static final String ARTIFACT_CATEGORY_BLUEPRINT = "blueprint";
+
+ protected BlueprintManifest manifest = null;
+
@Override
public void setContent(Object content) {
super.setContent(content);
@@ -63,8 +57,17 @@ public class Blueprint extends DefaultArtifact {
e.printStackTrace();
}
}
- }
+ }
+ @Override
+ public ArtifactManifest getManifest() {
+ if (this.manifest == null)
+ this.manifest = new BlueprintManifest(this);
+ if (this.content instanceof Document)
+ this.manifest.load((Document)this.content);
+ return this.manifest;
+ }
+
@Override
public void toFile(File destination) {
if (this.content instanceof String)
@@ -72,18 +75,17 @@ public class Blueprint extends DefaultArtifact {
else if (this.content instanceof Document) {
Document doc = (Document)this.content;
try {
- prepareManifest(doc);
+ asByteArray();
CommonXMLUtils.saveDocument(doc, destination);
} catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ log.error("Error saving to file", e);
}
}
else if (this.content instanceof byte[]) {
// TODO to be implemented
}
- }
+ }
@Override
public byte[] asByteArray() {
@@ -94,91 +96,14 @@ public class Blueprint extends DefaultArtifact {
if (this.content instanceof Document)
try {
Document doc = (Document)this.content;
- prepareManifest(doc);
+ if (!this.manifest.isLoaded())
+ this.manifest.load(doc);
+ this.manifest.save(doc);
return CommonXMLUtils.doc2string(doc).getBytes();
} catch (Exception e) {
- e.printStackTrace();
+ log.error("Error getting as byte[]: " + this.getCoordinates().toString(), e);
}
return new byte[] {};
}
- protected void prepareManifest(Document doc) {
- Manifest m = new Manifest();
- m.getMainAttributes().putValue("Manifest-Version", "2");
- m.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
- m.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME
- , this.coordinates.getGroupId() + "." + this.coordinates.getArtifactId());
- m.getMainAttributes().putValue(Constants.BUNDLE_NAME
- , this.coordinates.getGroupId() + "." + this.coordinates.getArtifactId());
- m.getMainAttributes().putValue(Constants.BUNDLE_VERSION, this.coordinates.getVersion().replaceAll("-", "."));
- m.getMainAttributes().putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
-
- m.getMainAttributes().putValue(Artifact.MANIFEST_HEADER_ENTAXY_BUNLDE, "true");
- m.getMainAttributes().putValue(Artifact.MANIFEST_HEADER_ENTAXY_RUNTIME, "true");
-
- NodeList l = doc.getElementsByTagName("manifest");
- if (l != null) {
- for (int i = 0; i < l.getLength(); i++) {
- Element e = (Element) l.item(i);
- String text = e.getTextContent();
- Properties props = new Properties();
- try {
- props.load(new ByteArrayInputStream(text.trim().getBytes()));
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- Enumeration en = props.propertyNames();
- while (en.hasMoreElements()) {
- String k = (String) en.nextElement();
- String v = props.getProperty(k);
- m.getMainAttributes().putValue(k, v);
- }
- e.getParentNode().removeChild(e);
- }
- }
-
- // add capabilities info
- String requiredCapabilities = getRequiredCapabilitiesValue();
- String providedCapabilities = getProvidedCapabilitiesValue();
-
- if (CommonUtils.isValid(requiredCapabilities)) {
- Object v = m.getMainAttributes().get(Constants.REQUIRE_CAPABILITY);
- String value = (v==null?"":v.toString());
- if (CommonUtils.isValid(value))
- value += "," + requiredCapabilities;
- else
- value = requiredCapabilities;
- m.getMainAttributes().putValue(Constants.REQUIRE_CAPABILITY, value);
- }
-
- if (CommonUtils.isValid(providedCapabilities)) {
- Object v = m.getMainAttributes().get(Constants.PROVIDE_CAPABILITY);
- String value = (v==null?"":v.toString());
- if (CommonUtils.isValid(value))
- value += "," + providedCapabilities;
- else
- value = providedCapabilities;
- m.getMainAttributes().putValue(Constants.PROVIDE_CAPABILITY, value);
- }
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- String manifestContent = "";
- try {
- m.write(bos);
- manifestContent = bos.toString(StandardCharsets.ISO_8859_1);
- manifestContent = manifestContent.replaceAll("\r", "").replaceAll("\n ", "");
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- Element manifest = doc.createElementNS("http://karaf.apache.org/xmlns/deployer/blueprint/v1.0.0", "manifest");
- manifest.setTextContent(manifestContent);
- doc.getDocumentElement().insertBefore(manifest, doc.getDocumentElement().getFirstChild());
-
- // copy manifest data to artifact properties
- for (Object key: m.getMainAttributes().keySet()) {
- this.properties.put(key.toString(), m.getMainAttributes().get(key));
- }
- }
}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/BlueprintManifest.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/BlueprintManifest.java
new file mode 100644
index 00000000..2be790b0
--- /dev/null
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/BlueprintManifest.java
@@ -0,0 +1,143 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.artifact;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.jar.Manifest;
+
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class BlueprintManifest implements ArtifactManifest {
+
+ private static final Logger log = LoggerFactory.getLogger(BlueprintManifest.class);
+
+ protected Artifact artifact;
+
+ protected Manifest manifest = new Manifest();
+
+ boolean isLoaded = false;
+
+ protected Map customAttributes = new HashMap<>();
+
+ public BlueprintManifest(Artifact artifact) {
+ super();
+ this.artifact = artifact;
+ }
+
+ public void load(Document document) {
+ this.isLoaded = false;
+ manifest = new Manifest();
+
+ manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.getMainAttributes().putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
+
+ manifest.getMainAttributes().putValue(HEADERS.ENTAXY_BUNDLE, "true");
+ manifest.getMainAttributes().putValue(HEADERS.ENTAXY_RUNTIME, "true");
+
+ NodeList l = document.getElementsByTagName("manifest");
+ if (l != null) {
+ for (int i = 0; i < l.getLength(); i++) {
+ Element e = (Element) l.item(i);
+ String text = e.getTextContent();
+ Properties props = new Properties();
+ try {
+ props.load(new ByteArrayInputStream(text.trim().getBytes()));
+ } catch (IOException e1) {
+ log.error("Error loading manifest", e1);
+ }
+ Enumeration en = props.propertyNames();
+ while (en.hasMoreElements()) {
+ String k = (String) en.nextElement();
+ String v = props.getProperty(k);
+ manifest.getMainAttributes().putValue(k, v);
+ }
+ e.getParentNode().removeChild(e);
+ }
+ }
+ this.isLoaded = true;
+ }
+
+ protected void appendCustoms(Document document) {
+ for (Entry entry: this.customAttributes.entrySet())
+ this.manifest.getMainAttributes().putValue(entry.getKey(), entry.getValue());
+ }
+
+ protected void beforeSave(Document document) {
+ this.manifest.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME
+ , this.artifact.getCoordinates().getGroupId() + "." + this.artifact.getCoordinates().getArtifactId());
+ this.manifest.getMainAttributes().putValue(Constants.BUNDLE_NAME
+ , this.artifact.getCoordinates().getGroupId() + "." + this.artifact.getCoordinates().getArtifactId());
+ this.manifest.getMainAttributes().putValue(Constants.BUNDLE_VERSION
+ , this.artifact.getCoordinates().getVersion().replaceAll("-", "."));
+ appendCustoms(document);
+ }
+
+ public void save(Document document) {
+ beforeSave(document);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ String manifestContent = "";
+ try {
+ this.manifest.write(bos);
+ manifestContent = bos.toString(StandardCharsets.ISO_8859_1);
+ manifestContent = manifestContent.replaceAll("\r", "").replaceAll("\n ", "");
+ } catch (IOException e) {
+ log.error("Error saving manifest to document", e);
+ }
+
+ // remove old manifests
+ NodeList l = document.getElementsByTagName("manifest");
+ if (l != null)
+ for (int i = 0; i < l.getLength(); i++) {
+ Element e = (Element) l.item(i);
+ e.getParentNode().removeChild(e);
+ }
+
+
+ Element manifest = document.createElementNS("http://karaf.apache.org/xmlns/deployer/blueprint/v1.0.0", "manifest");
+ manifest.setTextContent(manifestContent);
+ document.getDocumentElement().insertBefore(manifest
+ , document.getDocumentElement().getFirstChild());
+
+ }
+
+ @Override
+ public Map getCustomAttributes() {
+ return this.customAttributes;
+ }
+
+ public boolean isLoaded() {
+ return isLoaded;
+ }
+
+}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/DefaultArtifact.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/DefaultArtifact.java
index 5b217bf5..2c26969e 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/DefaultArtifact.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/DefaultArtifact.java
@@ -31,6 +31,7 @@ import java.util.Map;
import org.apache.camel.tooling.model.Strings;
import ru.entaxy.platform.core.artifact.annotation.ArtifactSupport;
+import ru.entaxy.platform.core.artifact.capabilities.CapabilityDescriptor;
import ru.entaxy.platform.core.artifact.impl.CapabilityDescriptorImpl;
public class DefaultArtifact implements Artifact {
@@ -92,7 +93,7 @@ public class DefaultArtifact implements Artifact {
}
protected void checkSetContent(Object content) {
- // TODO throw exception if content suites none of the supported clssses
+ // TODO throw exception if content suites none of the supported classes
if (this.supportedContentClasses.contains(content.getClass()))
this.content = content;
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Manifested.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Manifested.java
new file mode 100644
index 00000000..58a0ef46
--- /dev/null
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/Manifested.java
@@ -0,0 +1,26 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.artifact;
+
+public interface Manifested {
+
+ public ArtifactManifest getManifest();
+
+}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityDescriptor.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityDescriptor.java
new file mode 100644
index 00000000..fe6131c9
--- /dev/null
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityDescriptor.java
@@ -0,0 +1,60 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * artifact-management
+ * ==========
+ * Copyright (C) 2020 - 2021 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.artifact.capabilities;
+
+import org.osgi.resource.Capability;
+import java.util.Map;
+
+public interface CapabilityDescriptor extends Capability {
+
+ public static final String HEADER_PROVIDE_CAPABILITY = "Provide-Capability";
+ public static final String HEADER_REQUIRE_CAPABILITY = "Require-Capability";
+
+ public static interface ATTRIBUTE_TYPES {
+
+ public static final String STRING = "String";
+ public static final String VERSION = "Version";
+ public static final String LONG = "Long";
+ public static final String DOUBLE = "Double";
+ public static final String LIST = "List";
+
+ public static String TYPED_LIST(String itemType) {
+ return LIST + "<" + itemType + ">";
+ }
+
+ public static boolean isList(String itemType) {
+ return (itemType!=null) && (itemType.startsWith(LIST));
+ }
+
+ public static String itemType(String listType) {
+ if (!isList(listType))
+ return null;
+
+ return listType.substring(listType.indexOf("<"), listType.indexOf(">"));
+ }
+
+ }
+
+ public CapabilityDescriptor namespace(String namespace);
+ public CapabilityDescriptor attributes(Map attributes);
+ public CapabilityDescriptor attribute(String name, Object value);
+ public CapabilityDescriptor attribute(String name, Object value, String type);
+
+}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityDescriptorImpl.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityDescriptorImpl.java
new file mode 100644
index 00000000..4cbfd39e
--- /dev/null
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityDescriptorImpl.java
@@ -0,0 +1,158 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * artifact-management
+ * ==========
+ * Copyright (C) 2020 - 2021 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.artifact.capabilities;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import org.osgi.resource.Resource;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+
+public class CapabilityDescriptorImpl implements CapabilityDescriptor {
+
+ protected String namespace;
+
+ protected Map directives = new HashMap<>();
+ protected Map attributes = new HashMap<>();
+
+ private static class AttributeDescriptor {
+ String type;
+ Object value;
+
+ public AttributeDescriptor(Object value) {
+ this(value, CapabilityTypeHelper.getTypeName(value));
+ }
+
+ public AttributeDescriptor(Object value, String type) {
+ this.type = type;
+ this.value = value==null?"":value.toString();
+ }
+
+ public String getValueAsString() {
+ if (value == null)
+ return null;
+ if (CapabilityDescriptor.ATTRIBUTE_TYPES.isList(type))
+ return CapabilityTypeHelper.getListAsString((List>)value);
+ return value.toString();
+ }
+
+ }
+
+ public CapabilityDescriptorImpl() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public CapabilityDescriptorImpl(String namespace) {
+ this();
+ namespace(namespace);
+ }
+
+ public String getAttributesAsString() {
+ return this.attributes.entrySet().stream()
+ .map(entry->
+ entry.getKey()
+ + (!ATTRIBUTE_TYPES.STRING.equals(entry.getValue().type)?(":" + entry.getValue().type):"")
+ + "=" + entry.getValue().getValueAsString())
+ .collect(Collectors.joining(";"));
+ }
+
+ @Override
+ public String getNamespace() {
+ return this.namespace;
+ }
+
+ @Override
+ public Map getDirectives() {
+ return this.directives;
+ }
+
+ @Override
+ public Map getAttributes() {
+ Map result = new HashMap<>();
+ for (Map.Entry entry: this.attributes.entrySet())
+ result.put(entry.getKey(), entry.getValue().value);
+ return result;
+ }
+
+ @Override
+ public Resource getResource() {
+ // not implemented
+ return null;
+ }
+
+ @Override
+ public CapabilityDescriptor namespace(String namespace) {
+ this.namespace = namespace;
+ return this;
+ }
+
+ @Override
+ public CapabilityDescriptor attribute(String name, Object value) {
+ this.attributes.put(name, new AttributeDescriptor(value));
+ return this;
+ }
+
+ @Override
+ public CapabilityDescriptor attribute(String name, Object value, String type) {
+ this.attributes.put(name, new AttributeDescriptor(value, type));
+ return this;
+ }
+
+ public CapabilityDescriptor parseAttribute(String attributeData) {
+
+ String nameType = attributeData.substring(0, attributeData.indexOf("="));
+ if (!CommonUtils.isValid(nameType))
+ return this;
+ String[] nameTypeSplit = nameType.split(":");
+
+ String name = nameTypeSplit[0].trim();
+
+ String type = (nameTypeSplit.length > 1?nameTypeSplit[1]:CapabilityDescriptor.ATTRIBUTE_TYPES.STRING);
+ if (!CommonUtils.isValid(type))
+ type = CapabilityDescriptor.ATTRIBUTE_TYPES.STRING;
+ type = type.trim();
+
+ String value = attributeData.substring(attributeData.indexOf("=")+1);
+ if (!CommonUtils.isValid(value))
+ value = "";
+ value = value.trim();
+
+ Object typedValue = CapabilityTypeHelper.getTypedValue(type, value);
+ this.attribute(name, typedValue, type);
+
+ return this;
+ }
+
+
+ @Override
+ public CapabilityDescriptor attributes(Map attributes) {
+ if (attributes == null)
+ return this;
+ for (Entry entry: attributes.entrySet()) {
+ this.attribute(entry.getKey(), entry.getValue());
+ }
+ return this;
+ }
+
+}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityTypeHelper.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityTypeHelper.java
new file mode 100644
index 00000000..414f2266
--- /dev/null
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/CapabilityTypeHelper.java
@@ -0,0 +1,109 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.artifact.capabilities;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.core.artifact.capabilities.CapabilityDescriptor.ATTRIBUTE_TYPES;
+
+public class CapabilityTypeHelper {
+
+ public static String getTypeName(Object object) {
+
+ if (object == null)
+ return ATTRIBUTE_TYPES.STRING;
+
+ if (object instanceof List>) {
+ return ATTRIBUTE_TYPES.TYPED_LIST(getListTypeName((List>)object));
+ }
+ return getScalarTypeName(object);
+
+ }
+
+ public static String getListTypeName(List> list) {
+ if (list.size() == 0)
+ return ATTRIBUTE_TYPES.STRING;
+ else
+ return getScalarTypeName(list.get(0));
+ }
+
+ public static String getScalarTypeName(Object object) {
+ if ((object instanceof Integer) || (object instanceof Long))
+ return ATTRIBUTE_TYPES.LONG;
+ if (object instanceof Number)
+ return ATTRIBUTE_TYPES.DOUBLE;
+ return ATTRIBUTE_TYPES.STRING;
+ }
+
+ public static String getListAsString(List> list) {
+
+ String result = "\"";
+ if (list != null)
+ result += list.stream().map(item->(item==null)?"":item.toString())
+ .collect(Collectors.joining(","));
+
+ return result + "\"";
+ }
+
+ public static Object getTypedValue(String type, String value) {
+ if (CapabilityDescriptor.ATTRIBUTE_TYPES.STRING.equals(type))
+ return value;
+ if (CapabilityDescriptor.ATTRIBUTE_TYPES.VERSION.equals(type))
+ return value;
+ if (CapabilityDescriptor.ATTRIBUTE_TYPES.LONG.equals(type))
+ try {
+ return Long.parseLong(value);
+ } catch (Exception e) {
+ return Long.valueOf(-1);
+ }
+ if (CapabilityDescriptor.ATTRIBUTE_TYPES.DOUBLE.equals(type))
+ try {
+ return Double.parseDouble(value);
+ } catch (Exception e) {
+ return Double.valueOf(-1);
+ }
+ if (CapabilityDescriptor.ATTRIBUTE_TYPES.isList(type)) {
+ String itemType = CapabilityDescriptor.ATTRIBUTE_TYPES.itemType(type);
+ if (!CommonUtils.isValid(itemType))
+ return value;
+ List result = new ArrayList<>();
+ String val = value;
+ if (val.startsWith("\""))
+ val = val.substring(1);
+ if (val.endsWith("\""))
+ val = val.substring(0, val.length()-1);
+ if (!CommonUtils.isValid(val))
+ return result;
+
+ String[] vals = val.split(",");
+ for (int i=0; i< vals.length; i++)
+ if (vals[i] == null)
+ continue;
+ else
+ result.add(getTypedValue(itemType, vals[i]));
+ return result;
+ }
+
+ return value;
+ }
+}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/ManifestCapabilityHelper.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/ManifestCapabilityHelper.java
new file mode 100644
index 00000000..0b95ed99
--- /dev/null
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/capabilities/ManifestCapabilityHelper.java
@@ -0,0 +1,136 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.artifact.capabilities;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.core.artifact.ArtifactManifest;
+
+public class ManifestCapabilityHelper {
+
+ protected ArtifactManifest manifest;
+
+ protected Map requiredCapabilities = new HashMap<>();
+ protected Map providedCapabilities = new HashMap<>();
+
+ public ManifestCapabilityHelper(ArtifactManifest manifest) {
+ super();
+ this.manifest = manifest;
+ this.load();
+ }
+
+ protected void load() {
+ String existing = this.manifest.getCustomAttributes().get(CapabilityDescriptor.HEADER_PROVIDE_CAPABILITY);
+ if (CommonUtils.isValid(existing)) {
+ List list = parse(existing);
+ for (CapabilityDescriptorImpl c: list)
+ addProvidedCapability(c);
+ }
+ existing = this.manifest.getCustomAttributes().get(CapabilityDescriptor.HEADER_REQUIRE_CAPABILITY);
+ if (CommonUtils.isValid(existing)) {
+ List list = parse(existing);
+ for (CapabilityDescriptorImpl c: list)
+ addRequiredCapability(c);
+ }
+ }
+
+ protected void addProvidedCapability(CapabilityDescriptorImpl capabilityDescriptorImpl) {
+ if (capabilityDescriptorImpl == null)
+ return;
+ this.providedCapabilities.put(capabilityDescriptorImpl.getNamespace(), capabilityDescriptorImpl);
+ }
+
+ protected void addRequiredCapability(CapabilityDescriptorImpl capabilityDescriptorImpl) {
+ if (capabilityDescriptorImpl == null)
+ return;
+ this.requiredCapabilities.put(capabilityDescriptorImpl.getNamespace(), capabilityDescriptorImpl);
+ }
+
+ protected List parse(String capabilities) {
+ List result = new ArrayList<>();
+ String[] caps = capabilities.split(",");
+ for (int i=0; i< caps.length; i++)
+ if (CommonUtils.isValid(caps[i])) {
+ result.add(parseCapability(caps[i]));
+ }
+ return result;
+ }
+
+ protected CapabilityDescriptorImpl parseCapability(String capability) {
+ String[] parsed = capability.split(";");
+ CapabilityDescriptorImpl result = new CapabilityDescriptorImpl(parsed[0].trim());
+ for (int i=1; i getProvidedCapabilities(){
+ return this.providedCapabilities.values().stream()
+ .map(c -> (CapabilityDescriptor)c)
+ .collect(Collectors.toList());
+ }
+
+ public List getRequiredCapabilities(){
+ return this.requiredCapabilities.values().stream()
+ .map(c -> (CapabilityDescriptor)c)
+ .collect(Collectors.toList());
+ }
+
+ public boolean isCapabilityProvided(String namespace) {
+ return this.providedCapabilities.containsKey(namespace);
+ }
+
+ public boolean isCapabilityRequired(String namespace) {
+ return this.requiredCapabilities.containsKey(namespace);
+ }
+
+ public CapabilityDescriptor provideCapability(String namespace) {
+ if (!this.providedCapabilities.containsKey(namespace))
+ this.providedCapabilities.put(namespace, new CapabilityDescriptorImpl(namespace));
+ return this.providedCapabilities.get(namespace);
+ }
+
+ public CapabilityDescriptor requireCapability(String namespace) {
+ if (!this.requiredCapabilities.containsKey(namespace))
+ this.requiredCapabilities.put(namespace, new CapabilityDescriptorImpl(namespace));
+ return this.requiredCapabilities.get(namespace);
+ }
+
+ public void save() {
+ this.manifest.getCustomAttributes().put(CapabilityDescriptor.HEADER_PROVIDE_CAPABILITY,
+ this.providedCapabilities.values().stream()
+ .map(
+ cap -> (
+ cap.getNamespace()
+ + ";"
+ + cap.getAttributesAsString()
+ )
+ )
+ .collect(Collectors.joining(","))
+ );
+ }
+
+}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/impl/CapabilityDescriptorImpl.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/impl/CapabilityDescriptorImpl.java
index f252bb45..43ffc40d 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/impl/CapabilityDescriptorImpl.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/impl/CapabilityDescriptorImpl.java
@@ -24,8 +24,9 @@ import java.util.Map;
import org.osgi.resource.Resource;
-import ru.entaxy.platform.core.artifact.CapabilityDescriptor;
+import ru.entaxy.platform.core.artifact.capabilities.CapabilityDescriptor;
+@Deprecated(forRemoval = true, since = "1.8.2")
public class CapabilityDescriptorImpl implements CapabilityDescriptor {
protected String namespace;
@@ -103,16 +104,24 @@ public class CapabilityDescriptorImpl implements CapabilityDescriptor {
return this;
}
+
+
@Override
- public CapabilityDescriptor attribute(String name, String value) {
- this.attributes.put(name, new AttributeDescriptor(value));
- return this;
+ public CapabilityDescriptor attributes(Map attributes) {
+ // TODO Auto-generated method stub
+ return null;
}
@Override
- public CapabilityDescriptor attribute(String name, String value, String type) {
- this.attributes.put(name, new AttributeDescriptor(value, type));
- return this;
+ public CapabilityDescriptor attribute(String name, Object value) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public CapabilityDescriptor attribute(String name, Object value, String type) {
+ // TODO Auto-generated method stub
+ return null;
}
}
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/AbstractInstaller.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/AbstractInstaller.java
index 8ce6f180..f07e9d18 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/AbstractInstaller.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/AbstractInstaller.java
@@ -47,7 +47,7 @@ public abstract class AbstractInstaller, H extends TypedI
protected String bundleName = null;
protected Map> typedInstallerClasses = new HashMap<>();
- protected Map, Class extends H>> typedHelpeClasses = new HashMap<>();
+ protected Map, Class extends H>> typedHelperClasses = new HashMap<>();
// for BundleInstaller implementation
@@ -57,7 +57,7 @@ public abstract class AbstractInstaller, H extends TypedI
protected AbstractInstaller() {
this.typedInstallerClasses = new HashMap<>();
- this.typedHelpeClasses = new HashMap<>();
+ this.typedHelperClasses = new HashMap<>();
}
protected void doCreateTypedInstaller(Class extends TypedInstallerImpl> clazz) {
@@ -114,7 +114,7 @@ public abstract class AbstractInstaller, H extends TypedI
}
protected H createHelper() {
- Class extends H> clazz = typedHelpeClasses.get(typedInstaller.getClass());
+ Class extends H> clazz = typedHelperClasses.get(typedInstaller.getClass());
if (clazz == null)
return createDefaultHelper();
Constructor> constructor;
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/ClusterCommonBundleInstallerHelper.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/ClusterCommonBundleInstallerHelper.java
index aab68ce6..9197aee0 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/ClusterCommonBundleInstallerHelper.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/ClusterCommonBundleInstallerHelper.java
@@ -75,7 +75,7 @@ public class ClusterCommonBundleInstallerHelper extends ClusterTypedInstallerHel
.failed("Can't install/update: CellarBundleMBean not available");
}
- // TODO decide if we really need several grouos
+ // TODO decide if we really need several groups
// now we use only the first one
String groupToInstall = groupsToInstall.get(0);
@@ -198,7 +198,7 @@ public class ClusterCommonBundleInstallerHelper extends ClusterTypedInstallerHel
.failed("Can't install/update: CellarBundleMBean not available");
}
- // TODO decide if we really need several grouos
+ // TODO decide if we really need several groups
// now we use only the first one
String groupToInstall = groupsToInstall.get(0);
String bundleId = this.config.getBundleId();
diff --git a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/DefaultCellarInstaller.java b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/DefaultCellarInstaller.java
index f4923efc..0f81d960 100644
--- a/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/DefaultCellarInstaller.java
+++ b/platform/runtime/core/artifact-management/src/main/java/ru/entaxy/platform/core/artifact/installer/builder/impl/cluster/DefaultCellarInstaller.java
@@ -48,11 +48,11 @@ public class DefaultCellarInstaller extends AbstractInstaller
ru.entaxy.esb.platform.runtime.core
cluster
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.cluster
cluster-persistence-service
diff --git a/platform/runtime/core/cluster/pom.xml b/platform/runtime/core/cluster/pom.xml
index c008577b..5511493f 100644
--- a/platform/runtime/core/cluster/pom.xml
+++ b/platform/runtime/core/cluster/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime
core
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core
cluster
diff --git a/platform/runtime/core/infrastructure/pom.xml b/platform/runtime/core/infrastructure/pom.xml
index 4c92a8f9..7458c9e0 100644
--- a/platform/runtime/core/infrastructure/pom.xml
+++ b/platform/runtime/core/infrastructure/pom.xml
@@ -7,7 +7,7 @@
ru.entaxy.esb.platform.runtime
core
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core
diff --git a/platform/runtime/core/infrastructure/schema/pom.xml b/platform/runtime/core/infrastructure/schema/pom.xml
index 14707221..b2d42c09 100644
--- a/platform/runtime/core/infrastructure/schema/pom.xml
+++ b/platform/runtime/core/infrastructure/schema/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core
infrastructure
- 1.8.1
+ 1.8.2
4.0.0
pom
diff --git a/platform/runtime/core/infrastructure/schema/schema-api/pom.xml b/platform/runtime/core/infrastructure/schema/schema-api/pom.xml
index 9009b157..728af978 100644
--- a/platform/runtime/core/infrastructure/schema/schema-api/pom.xml
+++ b/platform/runtime/core/infrastructure/schema/schema-api/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core.infrastructure
schema
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/core/infrastructure/schema/schema-api/src/main/java/ru/entaxy/esb/platform/runtime/core/infrastructure/schema/api/entity/Resource.java b/platform/runtime/core/infrastructure/schema/schema-api/src/main/java/ru/entaxy/esb/platform/runtime/core/infrastructure/schema/api/entity/Resource.java
index da8798d7..f5cbef0b 100644
--- a/platform/runtime/core/infrastructure/schema/schema-api/src/main/java/ru/entaxy/esb/platform/runtime/core/infrastructure/schema/api/entity/Resource.java
+++ b/platform/runtime/core/infrastructure/schema/schema-api/src/main/java/ru/entaxy/esb/platform/runtime/core/infrastructure/schema/api/entity/Resource.java
@@ -19,7 +19,10 @@
*/
package ru.entaxy.esb.platform.runtime.core.infrastructure.schema.api.entity;
+import org.hibernate.annotations.Type;
+
import javax.persistence.*;
+import java.sql.Blob;
import java.util.Arrays;
import java.util.Date;
@@ -31,6 +34,7 @@ public class Resource {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
+ @Lob
@Column(name = "resource_value")
private byte[] resourceValue;
@Column(name = "created_date")
diff --git a/platform/runtime/core/infrastructure/schema/schema-component/pom.xml b/platform/runtime/core/infrastructure/schema/schema-component/pom.xml
index 025745d2..663bc299 100644
--- a/platform/runtime/core/infrastructure/schema/schema-component/pom.xml
+++ b/platform/runtime/core/infrastructure/schema/schema-component/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core.infrastructure
schema
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/core/infrastructure/schema/schema-impl/pom.xml b/platform/runtime/core/infrastructure/schema/schema-impl/pom.xml
index 5b374bd7..64ab1abb 100644
--- a/platform/runtime/core/infrastructure/schema/schema-impl/pom.xml
+++ b/platform/runtime/core/infrastructure/schema/schema-impl/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core.infrastructure
schema
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/core/infrastructure/schema/schema-impl/src/main/resources/hibernate.cfg.xml b/platform/runtime/core/infrastructure/schema/schema-impl/src/main/resources/hibernate.cfg.xml
index 8578266e..541e4ea7 100644
--- a/platform/runtime/core/infrastructure/schema/schema-impl/src/main/resources/hibernate.cfg.xml
+++ b/platform/runtime/core/infrastructure/schema/schema-impl/src/main/resources/hibernate.cfg.xml
@@ -29,6 +29,7 @@
validate
true
+ false
diff --git a/platform/runtime/core/infrastructure/schema/schema-soap/pom.xml b/platform/runtime/core/infrastructure/schema/schema-soap/pom.xml
index d070e994..0c3ab3ca 100644
--- a/platform/runtime/core/infrastructure/schema/schema-soap/pom.xml
+++ b/platform/runtime/core/infrastructure/schema/schema-soap/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core.infrastructure
schema
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/core/initializer/connection-initializer/pom.xml b/platform/runtime/core/initializer/connection-initializer/pom.xml
index 57c5a479..7272e404 100644
--- a/platform/runtime/core/initializer/connection-initializer/pom.xml
+++ b/platform/runtime/core/initializer/connection-initializer/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core
initializer
- 1.8.1
+ 1.8.2
4.0.0
@@ -30,7 +30,7 @@
true
- ru.entaxy.esb.platform.runtime.core.initializer.connection.ConnectionInitializer?id=connections&repeat=true&depends-on=core,datasources
+ ru.entaxy.esb.platform.runtime.core.initializer.connection.ConnectionInitializer?id=connections&repeat=true&retries=10&interval=2000&depends-on=core,datasources
@@ -51,6 +51,11 @@
json
init-config
+
+ src/main/non-packaged-resources/etc/init/file-connections.json
+ json
+ init-config-files
+
@@ -84,5 +89,19 @@
base-support
${project.version}
+
+
+ ru.entaxy.esb.platform.runtime.core.object-producing
+
+ object-producer-api
+ ${project.version}
+
+
+
+ ru.entaxy.esb.platform.runtime.core.object-producing
+
+ object-producer-core
+ ${project.version}
+
\ No newline at end of file
diff --git a/platform/runtime/core/initializer/connection-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/connection/ConnectionInitializer.java b/platform/runtime/core/initializer/connection-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/connection/ConnectionInitializer.java
index ac325bcc..1a7fc839 100644
--- a/platform/runtime/core/initializer/connection-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/connection/ConnectionInitializer.java
+++ b/platform/runtime/core/initializer/connection-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/connection/ConnectionInitializer.java
@@ -23,16 +23,28 @@ import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.gson.JsonObject;
+
import ru.entaxy.esb.platform.runtime.core.initializer.api.AbstractInitializer;
import ru.entaxy.esb.platform.runtime.core.initializer.api.InitializerException;
import ru.entaxy.esb.platform.runtime.core.management.connection.util.ConnectionManagerUtil;
import ru.entaxy.platform.base.support.FileUtils;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.base.support.osgi.OSGIUtils;
+import ru.entaxy.platform.core.artifact.ArtifactCoordinates;
+import ru.entaxy.platform.core.artifact.service.ArtifactService;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerUtils;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
import java.io.File;
+import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
+import java.util.List;
+import java.util.stream.Collectors;
public class ConnectionInitializer extends AbstractInitializer {
@@ -41,22 +53,49 @@ public class ConnectionInitializer extends AbstractInitializer {
private static final String JSON_FILE_NAME = "entaxy-platform-connections.json";
private static final String jsonBundlePath = "/connection/" + JSON_FILE_NAME;
-
- private static final String JSON_FILE_PATH = System.getProperty("karaf.etc")
+
+ private static final String INIT_FILES_PATH = System.getProperty("karaf.etc")
+ File.separator
- + "init"
+ + "init";
+
+ private static final String JSON_FILE_PATH = INIT_FILES_PATH
+ File.separator
+ JSON_FILE_NAME;
+ private EntaxyProducerService entaxyProducerService;
+
@Override
public void init() throws InitializerException {
log.info("ConnectionInitializer started");
log.info("-->> " + JSON_FILE_PATH);
+
+ try {
+ entaxyProducerService = OSGIUtils.services().bundleContext(bundleContext)
+ .ofClass(EntaxyProducerService.class)
+ .waitService(50000)
+ .get();
+ if (entaxyProducerService == null)
+ throw new InitializerException(this, "Service EntaxyProducerService not found", "", null);
+ } catch (Exception e) {
+ log.error("Error getting EntaxyProducerService", e);
+ throw new InitializerException(this, "Error getting EntaxyProducerService", "", e);
+ }
+
+ // first scan factory-base files
+ try {
+ scanAndInitFromFactoryFiles();
+ } catch (Exception e) {
+ log.error("Error initializing connections from factory files", e);
+ throw new InitializerException(this, "Can't create platform connections", "", e);
+ }
+
+
+ // then use the old one
try {
initPlatformConnections(bundleContext);
} catch (Exception e) {
- e.printStackTrace();
+ log.error("Error initializing connections from " + JSON_FILE_PATH, e);
throw new InitializerException(this, "Can't create platform connections", "", e);
}
}
@@ -64,16 +103,147 @@ public class ConnectionInitializer extends AbstractInitializer {
@Override
public void reinit() throws InitializerException {
// TODO Auto-generated method stub
+ }
+
+ private void scanAndInitFromFactoryFiles() throws Exception {
+
+ File initDir = new File(INIT_FILES_PATH);
+ if (!initDir.exists() || !initDir.isDirectory())
+ return;
+
+ File[] files = initDir.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".json") && !JSON_FILE_NAME.equals(name);
+ }
+ });
+
+ if ((files == null) || (files.length==0))
+ return;
+
+ for (int i=0; i factoryIds = objectModel.objects.stream()
+ .map(obj -> obj.factoryId)
+ .collect(Collectors.toList());
+ for (String factoryId: factoryIds) {
+ String message = "CHECK FACTORY :: " + factoryId + "..";
+ if (entaxyProducerService.findFactoryById(factoryId) == null) {
+ message += " NOT FOUND";
+ log.debug(message);
+ throw new InitializerException(this, "Factory not found: " + factoryId, "", null);
+ }
+ message += " FOUND";
+ log.debug(message);
+ }
+
+ log.debug("FACTORIES AVAILABLE :: " + files[i].getName());
+
+ //
+ // produce objects
+ //
+
+ EntaxyProducerUtils.InstructionsBuilder builder = EntaxyProducerUtils.instructions()
+ .any()
+ .command("add-config")
+ .command("pre-generate")
+ .set(EntaxyProducerService.INSTRUCTIONS.PRINT_OUTPUT, true)
+ .command("build")
+ .set(EntaxyProducerService.INSTRUCTIONS.ARTIFACT.VERSION_POLICY
+ , ArtifactCoordinates.VERSION_POLICY_DATED_EMBEDDED)
+ .command("deploy")
+ .set("deployLocal", true);
+
+ if (helper.isChanged()) {
+ log.info("File is new or changed, install/update connections: " + files[i].getAbsolutePath());
+ // we need to create/update connections with new timestamp
+ String oldTimestamp = helper.getTimestamp();
+ String newTimestamp = helper.updateTimestamp();
+
+ builder
+ .command("build")
+ .set(EntaxyProducerService.INSTRUCTIONS.ARTIFACT.TIMESTAMP, newTimestamp)
+ .command("install")
+ .set("update", "");
+
+ String instructions = builder
+ .getInstructionsString();
+
+ entaxyProducerService.produce(jsonData, instructions);
+
+ helper.updateMd5();
+ } else {
+ log.info("File is not changed, install/check connection: " + files[i].getAbsolutePath());
+
+ String oldTimestamp = helper.getTimestamp();
+
+ builder
+ .command("build")
+ .set(EntaxyProducerService.INSTRUCTIONS.ARTIFACT.TIMESTAMP, oldTimestamp)
+ .command("install")
+ .set("installOnlyIfMissing", true);
+
+ String instructions = builder
+ .getInstructionsString();
+
+ entaxyProducerService.produce(jsonData, instructions);
+ }
+
+
+ }
+
+
+
}
private void initPlatformConnections(BundleContext bundleContext) throws Exception {
- chackAndPrepareFile(bundleContext);
+ checkAndPrepareFile(bundleContext);
String json = getJsonAsString(bundleContext);
FileUtils.FileHelper helper = new FileUtils.FileHelper(JSON_FILE_PATH);
if (!helper.isReadable()) {
// TODO throw exception
- log.error("Platform connectons file {} is not readable", JSON_FILE_PATH);
+ log.error("Platform connections file {} is not readable", JSON_FILE_PATH);
return;
}
@@ -89,7 +259,7 @@ public class ConnectionInitializer extends AbstractInitializer {
helper.updateMd5();
} else {
log.info("File is not changed, install/check connections");
- // we need to create if absent connectoins with old timestamp
+ // we need to create if absent connections with old timestamp
// ConnectionManagerUtil.getService().createAndInstallConnections(json);
ConnectionManagerUtil.getService().checkInstallConnections(json, helper.getTimestamp());
}
@@ -97,7 +267,7 @@ public class ConnectionInitializer extends AbstractInitializer {
}
- private void chackAndPrepareFile(BundleContext context) throws IOException {
+ private void checkAndPrepareFile(BundleContext context) throws IOException {
File f = new File(JSON_FILE_PATH);
if (!f.exists()) {
FileUtils.string2file(getJsonAsString(context), JSON_FILE_PATH);
diff --git a/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/entaxy-platform-connections.json b/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/entaxy-platform-connections.json
index f6e93ac6..07db26f0 100644
--- a/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/entaxy-platform-connections.json
+++ b/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/entaxy-platform-connections.json
@@ -1,19 +1,5 @@
{
"connections": [
- {
- "nodeType": "connection",
- "uuid": "connection-uuid-1",
- "name": "entaxy-file",
- "adapterName": "fileAdapter",
- "platform": true,
- "pathParameter": "data/shared",
- "properties": {},
- "options": {
- "noop": true,
- "fileName": "default.txt",
- "allowNullBody": "true"
- }
- },
{
"nodeType": "connection",
"uuid": "connection-uuid-2",
@@ -34,7 +20,8 @@
"nodeType": "connection",
"uuid": "connection-uuid-3",
"name": "entaxy-db-storage",
- "adapterName": "postgresqlAdapter",
+ "adapterName.pg": "postgresqlAdapter",
+ "adapterName": "h2Adapter",
"platform": true,
"pathParameter": "entaxy.esb.storage",
"properties": {},
@@ -44,7 +31,8 @@
"nodeType": "connection",
"uuid": "connection-uuid-4",
"name": "entaxy-db-cache",
- "adapterName": "postgresqlAdapter",
+ "adapterName.pg": "postgresqlAdapter",
+ "adapterName": "h2Adapter",
"platform": true,
"pathParameter": "entaxy.esb.cache",
"properties": {},
diff --git a/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/file-connections.json b/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/file-connections.json
new file mode 100644
index 00000000..a7c94827
--- /dev/null
+++ b/platform/runtime/core/initializer/connection-initializer/src/main/non-packaged-resources/etc/init/file-connections.json
@@ -0,0 +1,29 @@
+{
+ "connections": [
+ {
+ "factoryId": "file-adapter",
+ "objectId": "entaxy-file",
+ "properties": {
+ "rootDirectory": "data/shared"
+ }
+ },
+ {
+ "factoryId": "file-adapter",
+ "objectId": "entaxy-file-internal",
+ "properties": {
+ "__parentConnection": {
+ "isRef": true,
+ "type": "entaxy.runtime.connection",
+ "required": true,
+ "isRefByValueOnly": true,
+ "refField": "rootDirectory",
+ "targetId": "entaxy-file"
+ },
+ "rootDirectory": {
+ "isCalculated": true,
+ "expression": "${__parentConnection}/.entaxy"
+ }
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/platform/runtime/core/initializer/connection-initializer/src/main/resources/connection/entaxy-platform-connections.json b/platform/runtime/core/initializer/connection-initializer/src/main/resources/connection/entaxy-platform-connections.json
deleted file mode 100644
index 74012b16..00000000
--- a/platform/runtime/core/initializer/connection-initializer/src/main/resources/connection/entaxy-platform-connections.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "connections": [
- {
- "nodeType": "connection",
- "uuid": "connection-uuid-1",
- "name": "entaxy-file",
- "adapterName": "fileAdapter",
- "platform": true,
- "pathParameter": "data/shared",
- "properties": {},
- "options": {
- "noop": true,
- "fileName": "default.txt",
- "allowNullBody": "true"
- }
- },
- {
- "nodeType": "connection",
- "uuid": "connection-uuid-2",
- "name": "entaxy-broker",
- "adapterName": "artemisAmqpAdapter",
- "platform": true,
- "pathParameter": "queue:entaxy.default",
- "properties": {
- "url": "amqp://localhost:5672",
- "username": "entaxy",
- "password": "entaxy"
- },
- "options": {}
- },
- {
- "nodeType": "connection",
- "uuid": "connection-uuid-3",
- "name": "entaxy-db-storage",
- "adapterName.pg": "postgresqlAdapter",
- "adapterName": "h2Adapter",
- "platform": true,
- "pathParameter": "entaxy.esb.storage",
- "properties": {},
- "options": {}
- },
- {
- "nodeType": "connection",
- "uuid": "connection-uuid-4",
- "name": "entaxy-db-cache",
- "adapterName.pg": "postgresqlAdapter",
- "adapterName": "h2Adapter",
- "platform": true,
- "pathParameter": "entaxy.esb.cache",
- "properties": {},
- "options": {}
- }
- ]
-}
diff --git a/platform/runtime/core/initializer/core-initializer/pom.xml b/platform/runtime/core/initializer/core-initializer/pom.xml
index 980d037b..2de23c10 100644
--- a/platform/runtime/core/initializer/core-initializer/pom.xml
+++ b/platform/runtime/core/initializer/core-initializer/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime.core
initializer
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.initializer
core-initializer
diff --git a/platform/runtime/core/initializer/datasources-initializer/pom.xml b/platform/runtime/core/initializer/datasources-initializer/pom.xml
index ddd599f2..efc89f4b 100644
--- a/platform/runtime/core/initializer/datasources-initializer/pom.xml
+++ b/platform/runtime/core/initializer/datasources-initializer/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime.core
initializer
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.initializer
datasources-initializer
diff --git a/platform/runtime/core/initializer/datasources-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/datasources/DataSourcesInitializer.java b/platform/runtime/core/initializer/datasources-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/datasources/DataSourcesInitializer.java
index 3b99c8f9..d52d646d 100644
--- a/platform/runtime/core/initializer/datasources-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/datasources/DataSourcesInitializer.java
+++ b/platform/runtime/core/initializer/datasources-initializer/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/datasources/DataSourcesInitializer.java
@@ -64,7 +64,7 @@ public class DataSourcesInitializer extends AbstractInitializer {
}
@Override
- public void setCalllback(Callback callback) {
+ public void setCallback(Callback callback) {
DataSourcesInitializer.callback = callback;
}
}
diff --git a/platform/runtime/core/initializer/init-manager/pom.xml b/platform/runtime/core/initializer/init-manager/pom.xml
index 6d3a4613..8e4a7bc1 100644
--- a/platform/runtime/core/initializer/init-manager/pom.xml
+++ b/platform/runtime/core/initializer/init-manager/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime.core
initializer
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.initializer
init-manager
diff --git a/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/InitManager.java b/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/InitManager.java
index 62f04184..2bdbbb9c 100644
--- a/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/InitManager.java
+++ b/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/InitManager.java
@@ -133,7 +133,7 @@ public class InitManager {
try {
this.retries = Integer.parseInt(retriesValue);
} catch (NumberFormatException e) {
- log.error("Retries paramater [{}] is not an integer", retriesValue);
+ log.error("Retries parameter [{}] is not an integer", retriesValue);
}
String intervalValue = params.get(Initializer.INITIALIZER_QUERY_STRING_PARAM_INTERVAL);
@@ -141,7 +141,7 @@ public class InitManager {
try {
this.interval = Integer.parseInt(intervalValue);
} catch (NumberFormatException e) {
- log.error("Interval paramater [{}] is not an integer", intervalValue);
+ log.error("Interval parameter [{}] is not an integer", intervalValue);
}
}
@@ -221,6 +221,12 @@ public class InitManager {
}
+ public void runInitializer() {
+ Thread thread = new Thread(new Executor(this));
+ thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
+ thread.start();
+ }
+
public void setCallback() {
BundleWiring wiring = getBundle().adapt(BundleWiring.class);
ClassLoader cl = wiring.getClassLoader();
@@ -230,7 +236,7 @@ public class InitManager {
log.info("Loaded class {}", clazz.getName());
Constructor> constructor = clazz.getConstructor();
Initializer initializer = (Initializer) constructor.newInstance();
- initializer.setCalllback(this);
+ initializer.setCallback(this);
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -241,7 +247,8 @@ public class InitManager {
synchronized (this.dependsOn) {
this.dependsOn.remove(meta.id);
if (!this.executed && this.canExecute())
- this.execute();
+ // this.execute();
+ this.runInitializer();
}
}
@@ -251,7 +258,7 @@ public class InitManager {
InitManager.this.updateById(id, true);
this.executed = true;
this.notifyDependent();
- owner.setCalllback(null);
+ owner.setCallback(null);
}
};
@@ -367,10 +374,12 @@ public class InitManager {
bundle.getBundleId(), bundle.getSymbolicName());
InitializerMeta meta = createMeta(initializerClass, bundle);
+
+ meta.runInitializer();
- Thread thread = new Thread(new Executor(meta));
- thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
- thread.start();
+// Thread thread = new Thread(new Executor(meta));
+// thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
+// thread.start();
}
diff --git a/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/AbstractInitializer.java b/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/AbstractInitializer.java
index d6501141..5c4915ab 100644
--- a/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/AbstractInitializer.java
+++ b/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/AbstractInitializer.java
@@ -53,7 +53,7 @@ public abstract class AbstractInitializer implements Initializer {
}
@Override
- public void setCalllback(Callback callback) {
+ public void setCallback(Callback callback) {
// Ignore it by default
}
}
diff --git a/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/Initializer.java b/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/Initializer.java
index 579c3150..0fd576c8 100644
--- a/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/Initializer.java
+++ b/platform/runtime/core/initializer/init-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/initializer/api/Initializer.java
@@ -61,5 +61,5 @@ public interface Initializer {
public void setInitializerId(String id);
public String getInitializerId();
- public void setCalllback(Initializer.Callback callback);
+ public void setCallback(Initializer.Callback callback);
}
diff --git a/platform/runtime/core/initializer/pom.xml b/platform/runtime/core/initializer/pom.xml
index 51fab9be..f650d9e2 100644
--- a/platform/runtime/core/initializer/pom.xml
+++ b/platform/runtime/core/initializer/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime
core
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core
initializer
diff --git a/platform/runtime/core/initializer/storage-initializer/cache/pom.xml b/platform/runtime/core/initializer/storage-initializer/cache/pom.xml
index c1d709bb..4de5f83f 100644
--- a/platform/runtime/core/initializer/storage-initializer/cache/pom.xml
+++ b/platform/runtime/core/initializer/storage-initializer/cache/pom.xml
@@ -6,7 +6,7 @@
storage-initializer
ru.entaxy.esb.platform.runtime.core.initializer
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.initializer.storage.initializer
diff --git a/platform/runtime/core/initializer/storage-initializer/esb_entaxy/pom.xml b/platform/runtime/core/initializer/storage-initializer/esb_entaxy/pom.xml
index e7834859..7bb9bb2f 100644
--- a/platform/runtime/core/initializer/storage-initializer/esb_entaxy/pom.xml
+++ b/platform/runtime/core/initializer/storage-initializer/esb_entaxy/pom.xml
@@ -6,7 +6,7 @@
storage-initializer
ru.entaxy.esb.platform.runtime.core.initializer
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.initializer.storage.initializer
diff --git a/platform/runtime/core/initializer/storage-initializer/esb_entaxy/src/main/resources/db/changeset/015-schema-table-create.xml b/platform/runtime/core/initializer/storage-initializer/esb_entaxy/src/main/resources/db/changeset/015-schema-table-create.xml
index 655b896d..46f9835b 100644
--- a/platform/runtime/core/initializer/storage-initializer/esb_entaxy/src/main/resources/db/changeset/015-schema-table-create.xml
+++ b/platform/runtime/core/initializer/storage-initializer/esb_entaxy/src/main/resources/db/changeset/015-schema-table-create.xml
@@ -25,7 +25,7 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
-
+
diff --git a/platform/runtime/core/initializer/storage-initializer/liquibase-updater/pom.xml b/platform/runtime/core/initializer/storage-initializer/liquibase-updater/pom.xml
index 692eee29..182ca7c8 100644
--- a/platform/runtime/core/initializer/storage-initializer/liquibase-updater/pom.xml
+++ b/platform/runtime/core/initializer/storage-initializer/liquibase-updater/pom.xml
@@ -5,7 +5,7 @@
storage-initializer
ru.entaxy.esb.platform.runtime.core.initializer
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/core/initializer/storage-initializer/pom.xml b/platform/runtime/core/initializer/storage-initializer/pom.xml
index 9c28fddf..2e97aa7e 100644
--- a/platform/runtime/core/initializer/storage-initializer/pom.xml
+++ b/platform/runtime/core/initializer/storage-initializer/pom.xml
@@ -5,7 +5,7 @@
ru.entaxy.esb.platform.runtime.core
initializer
- 1.8.1
+ 1.8.2
4.0.0
diff --git a/platform/runtime/core/management/blueprint-generator-service/pom.xml b/platform/runtime/core/management/blueprint-generator-service/pom.xml
index 7c669b83..233a0e49 100644
--- a/platform/runtime/core/management/blueprint-generator-service/pom.xml
+++ b/platform/runtime/core/management/blueprint-generator-service/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
blueprint-generator-service
diff --git a/platform/runtime/core/management/cluster-node-management/pom.xml b/platform/runtime/core/management/cluster-node-management/pom.xml
index 8627b628..76401481 100644
--- a/platform/runtime/core/management/cluster-node-management/pom.xml
+++ b/platform/runtime/core/management/cluster-node-management/pom.xml
@@ -3,7 +3,7 @@
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
cluster-node-management
diff --git a/platform/runtime/core/management/connection-management/pom.xml b/platform/runtime/core/management/connection-management/pom.xml
index f2d33c79..865e95ff 100644
--- a/platform/runtime/core/management/connection-management/pom.xml
+++ b/platform/runtime/core/management/connection-management/pom.xml
@@ -7,7 +7,7 @@
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
diff --git a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/ConnectionMBean.java b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/ConnectionMBean.java
index 51ce1114..9067477d 100644
--- a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/ConnectionMBean.java
+++ b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/ConnectionMBean.java
@@ -19,7 +19,9 @@
*/
package ru.entaxy.esb.platform.core.management.connection;
-public interface ConnectionMBean {
+import ru.entaxy.esb.platform.base.management.core.api.RuntimeTypedMBean;
+
+public interface ConnectionMBean extends RuntimeTypedMBean {
public static final String CONNECTION_KEY = "connection";
diff --git a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionMBeanImpl.java b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionMBeanImpl.java
index ce04493e..e2449a8e 100644
--- a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionMBeanImpl.java
+++ b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionMBeanImpl.java
@@ -25,8 +25,11 @@ import javax.management.StandardMBean;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import ru.entaxy.esb.platform.base.management.core.api.EntaxyRuntimeTyped;
import ru.entaxy.esb.platform.core.management.connection.ConnectionMBean;
+//@TODO move string to constant
+@EntaxyRuntimeTyped(name = "entaxy.runtime.connection")
public class ConnectionMBeanImpl extends StandardMBean implements ConnectionMBean {
protected ManagedConnection connection;
diff --git a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionsMBeanImpl.java b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionsMBeanImpl.java
index 3db43fb0..45c2fb02 100644
--- a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionsMBeanImpl.java
+++ b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ConnectionsMBeanImpl.java
@@ -91,7 +91,7 @@ public class ConnectionsMBeanImpl extends StandardMBean
}
@Override
- public void addded(ManagedConnections connections) {
+ public void added(ManagedConnections connections) {
Hashtable props = new Hashtable<>();
// String jmxObjectName = "jmx.objectname";
// String objectName = "ru.entaxy.esb:group=platform,category=connections,connection=";
@@ -108,6 +108,7 @@ public class ConnectionsMBeanImpl extends StandardMBean
descriptor.registration = bundleContext.registerService(ConnectionMBean.class
, service
, props);
+ managed.put(connection.getName(), descriptor);
} catch (Exception e) {
log.error("Error adding connection [" + connection.getName() + "]", e);
}
diff --git a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ManagedConnectionsListener.java b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ManagedConnectionsListener.java
index c3b6a6c8..f507e3a5 100644
--- a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ManagedConnectionsListener.java
+++ b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/impl/ManagedConnectionsListener.java
@@ -21,7 +21,7 @@ package ru.entaxy.esb.platform.core.management.connection.impl;
public interface ManagedConnectionsListener {
- public void addded(ManagedConnections connections);
+ public void added(ManagedConnections connections);
public void removed(ManagedConnections connections);
}
diff --git a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/tracker/DeployedConnectionCustomizer.java b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/tracker/DeployedConnectionCustomizer.java
index 22cf1047..75ebad3e 100644
--- a/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/tracker/DeployedConnectionCustomizer.java
+++ b/platform/runtime/core/management/connection-management/src/main/java/ru/entaxy/esb/platform/core/management/connection/tracker/DeployedConnectionCustomizer.java
@@ -26,6 +26,8 @@ import org.osgi.framework.BundleEvent;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import ru.entaxy.esb.platform.core.management.connection.ConnectionsMBean;
import ru.entaxy.esb.platform.core.management.connection.impl.ManagedConnection;
@@ -35,6 +37,8 @@ import ru.entaxy.platform.base.support.CommonUtils;
public class DeployedConnectionCustomizer implements BundleTrackerCustomizer {
+ private static final Logger log = LoggerFactory.getLogger(DeployedConnectionCustomizer.class);
+
protected ManagedConnectionsListener listener;
public DeployedConnectionCustomizer(ManagedConnectionsListener listener) {
@@ -43,16 +47,20 @@ public class DeployedConnectionCustomizer implements BundleTrackerCustomizer capabilities = revision.getDeclaredCapabilities(ConnectionsMBean.CAPABILITY_NAMESPACE);
if ((capabilities==null) || (capabilities.size()==0))
return null;
+ log.debug("CAPABILITIES FOUND: " + bundle.getBundleId());
ManagedConnections result = new ManagedConnections();
for (BundleCapability capability: capabilities) {
Object val = capability.getAttributes().get("name");
String name = val==null?"":val.toString();
+ log.debug("CAPABILITIES/NAME [" + name + "] : " + bundle.getBundleId());
if (!CommonUtils.isValid(name))
continue;
val = capability.getAttributes().get("platform");
@@ -66,7 +74,7 @@ public class DeployedConnectionCustomizer implements BundleTrackerCustomizer
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
diff --git a/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/api/ConnectionManager.java b/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/api/ConnectionManager.java
index 0c094fb5..6de70cd7 100644
--- a/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/api/ConnectionManager.java
+++ b/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/api/ConnectionManager.java
@@ -23,6 +23,7 @@ import ru.entaxy.esb.platform.runtime.base.connecting.connection.Connection;
import java.util.List;
+@Deprecated
public interface ConnectionManager {
/*
@Deprecated
diff --git a/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/impl/ConnectionManagerImpl.java b/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/impl/ConnectionManagerImpl.java
index 7b8e7225..71488e66 100644
--- a/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/impl/ConnectionManagerImpl.java
+++ b/platform/runtime/core/management/connection-manager/src/main/java/ru/entaxy/esb/platform/runtime/core/management/connection/impl/ConnectionManagerImpl.java
@@ -37,8 +37,11 @@ import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
import ru.entaxy.esb.platform.runtime.base.connecting.producer.connection.util.ConnectionProducerUtil;
import ru.entaxy.esb.platform.runtime.core.management.connection.api.ConnectionManager;
import ru.entaxy.platform.core.artifact.Artifact;
+import ru.entaxy.platform.core.artifact.ArtifactManifest;
import ru.entaxy.platform.core.artifact.Artifacts;
import ru.entaxy.platform.core.artifact.DeployedArtifact;
+import ru.entaxy.platform.core.artifact.Manifested;
+import ru.entaxy.platform.core.artifact.capabilities.ManifestCapabilityHelper;
import ru.entaxy.platform.core.artifact.installer.builder.Installer;
import ru.entaxy.platform.core.artifact.installer.builder.typed.BlueprintInstaller;
import ru.entaxy.platform.core.artifact.service.ArtifactService;
@@ -155,9 +158,16 @@ public class ConnectionManagerImpl implements ConnectionManager {
.timestampedVersion(version)
.groupId(Artifact.DEFAULT_RUNTIME_GROUP_ID + "." + type)
.artifactId(type + "-" + name);
- artifact.provideCapability(artifact.getCoordinates().getGroupId())
- .attribute("name",connection.getName())
- .attribute("platform", connection.isPlatform()?"true":"false");
+
+ if (artifact.isManifested()) {
+ ArtifactManifest manifest = ((Manifested)artifact).getManifest();
+ ManifestCapabilityHelper capabilityHelper = new ManifestCapabilityHelper(manifest);
+ capabilityHelper.provideCapability(artifact.getCoordinates().getGroupId())
+ .attribute("name",connection.getName())
+ .attribute("platform", connection.isPlatform()?"true":"false");
+ capabilityHelper.save();
+ }
+
log.info("Artifact of category [{}] is prepared: [{}]", artifact.getCategory(), artifact.getCoordinates());
return artifact;
} else {
diff --git a/platform/runtime/core/management/node-management/pom.xml b/platform/runtime/core/management/node-management/pom.xml
index fc5f5363..a07b329d 100644
--- a/platform/runtime/core/management/node-management/pom.xml
+++ b/platform/runtime/core/management/node-management/pom.xml
@@ -3,11 +3,10 @@
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
node-management
- 1.8.1
bundle
ENTAXY :: PLATFORM :: RUNTIME :: CORE :: MANAGEMENT :: NODE MANAGEMENT
ENTAXY :: PLATFORM :: RUNTIME :: CORE :: MANAGEMENT :: NODE MANAGEMENT
diff --git a/platform/runtime/core/management/pom.xml b/platform/runtime/core/management/pom.xml
index 2e8ae5e3..803bd51c 100644
--- a/platform/runtime/core/management/pom.xml
+++ b/platform/runtime/core/management/pom.xml
@@ -7,7 +7,7 @@
ru.entaxy.esb.platform.runtime
core
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core
diff --git a/platform/runtime/core/management/profile-management-service-adapters/pom.xml b/platform/runtime/core/management/profile-management-service-adapters/pom.xml
index 9245be2f..57b26811 100644
--- a/platform/runtime/core/management/profile-management-service-adapters/pom.xml
+++ b/platform/runtime/core/management/profile-management-service-adapters/pom.xml
@@ -7,7 +7,7 @@
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
diff --git a/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/ConnectorManagerAdapter.java b/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/ConnectorManagerAdapter.java
index cc8722d6..9b6f4867 100644
--- a/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/ConnectorManagerAdapter.java
+++ b/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/ConnectorManagerAdapter.java
@@ -52,14 +52,14 @@ public class ConnectorManagerAdapter implements ru.entaxy.esb.platform.core.mana
ConnectorService connectorService;
@Override
- public void addConnector(String idOrName, String connectorFactoryId, Map paramaters)
+ public void addConnector(String idOrName, String connectorFactoryId, Map parameters)
throws Exception {
System system = getSystemByIdOrName(idOrName);
if (system == null)
throw new IllegalArgumentException("System not found by Id or Name [" + idOrName + "]");
ConnectorDto connectorDto = new ConnectorDto();
- connectorDto.setConnectorParams(paramaters);
+ connectorDto.setConnectorParams(parameters);
connectorDto.setSystemUuid(system.getUuid());
connectorDto.setTemplateName(connectorFactoryId);
diff --git a/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/PermissionManagerAdapter.java b/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/PermissionManagerAdapter.java
index 2a09c5b0..fffebd84 100644
--- a/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/PermissionManagerAdapter.java
+++ b/platform/runtime/core/management/profile-management-service-adapters/src/main/java/ru/entaxy/esb/platform/core/management/profile/adapters/PermissionManagerAdapter.java
@@ -85,7 +85,7 @@ public class PermissionManagerAdapter implements ru.entaxy.esb.platform.core.man
}
@Override
- public void createPremission(String objectId, String subjectId) throws Exception {
+ public void createPermission(String objectId, String subjectId) throws Exception {
PermissionDto dto = new PermissionDto(objectId, subjectId);
permissionManager.createPermission(dto);
}
diff --git a/platform/runtime/core/management/profile-management/pom.xml b/platform/runtime/core/management/profile-management/pom.xml
index f435f156..948ac6d9 100644
--- a/platform/runtime/core/management/profile-management/pom.xml
+++ b/platform/runtime/core/management/profile-management/pom.xml
@@ -7,7 +7,7 @@
ru.entaxy.esb.platform.runtime.core
management
- 1.8.1
+ 1.8.2
ru.entaxy.esb.platform.runtime.core.management
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ConnectorMBean.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ConnectorMBean.java
index 979b6705..6facb190 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ConnectorMBean.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ConnectorMBean.java
@@ -24,10 +24,11 @@ import ru.entaxy.esb.platform.base.management.core.api.Attribute;
import ru.entaxy.esb.platform.base.management.core.api.MBeanAnnotated;
import ru.entaxy.esb.platform.base.management.core.api.MBeanExportPolicy;
import ru.entaxy.esb.platform.base.management.core.api.Operation;
+import ru.entaxy.esb.platform.base.management.core.api.RuntimeTypedMBean;
import ru.entaxy.esb.platform.base.management.core.utils.BundleAwareMBean;
@MBeanAnnotated(policy = MBeanExportPolicy.ANNOTATION_ENRICH)
-public interface ConnectorMBean extends BundleAwareMBean {
+public interface ConnectorMBean extends BundleAwareMBean, RuntimeTypedMBean {
public static interface Helper {
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/DefaultRouteMBean.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/DefaultRouteMBean.java
index 157bf84c..50f4f1e7 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/DefaultRouteMBean.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/DefaultRouteMBean.java
@@ -20,9 +20,10 @@
package ru.entaxy.esb.platform.core.management.profile;
import ru.entaxy.esb.platform.base.management.core.Qualifier;
+import ru.entaxy.esb.platform.base.management.core.api.RuntimeTypedMBean;
import ru.entaxy.esb.platform.base.management.core.utils.BundleAwareMBean;
-public interface DefaultRouteMBean extends BundleAwareMBean {
+public interface DefaultRouteMBean extends BundleAwareMBean, RuntimeTypedMBean {
public static interface Helper {
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ProfileMBean.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ProfileMBean.java
index 1394d254..43ee28a6 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ProfileMBean.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/ProfileMBean.java
@@ -30,10 +30,11 @@ import ru.entaxy.esb.platform.base.management.core.api.MBeanAnnotated;
import ru.entaxy.esb.platform.base.management.core.api.MBeanExportPolicy;
import ru.entaxy.esb.platform.base.management.core.api.Operation;
import ru.entaxy.esb.platform.base.management.core.api.Parameter;
+import ru.entaxy.esb.platform.base.management.core.api.RuntimeTypedMBean;
import ru.entaxy.esb.platform.base.management.core.utils.BundleAwareMBean;
@MBeanAnnotated(policy = MBeanExportPolicy.ANNOTATION_ENRICH)
-public interface ProfileMBean extends BundleAwareMBean {
+public interface ProfileMBean extends BundleAwareMBean, RuntimeTypedMBean {
public static interface Helper {
@@ -66,7 +67,7 @@ public interface ProfileMBean extends BundleAwareMBean {
@Operation(desc = "Adds connector to profile")
public void addConnector(
@Parameter(name = "factoryId", desc = "Connector factory ID") String connectorFactoryId
- , @Parameter(name = "parameters", desc = "Connector parameters") Map paramaters) throws Exception;
+ , @Parameter(name = "parameters", desc = "Connector parameters") Map parameters) throws Exception;
@Operation(desc = "Removes connector from profile")
public void removeConnector(
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/ConnectorManager.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/ConnectorManager.java
index e8dad00d..aca15ba9 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/ConnectorManager.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/ConnectorManager.java
@@ -23,7 +23,7 @@ import java.util.Map;
public interface ConnectorManager {
- public void addConnector(String idOrName, String connectorFactoryId, Map paramaters) throws Exception;
+ public void addConnector(String idOrName, String connectorFactoryId, Map parameters) throws Exception;
public void removeConnector(String idOrName, String connectorName) throws Exception;
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/PermissionManager.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/PermissionManager.java
index c4c12a9a..4b22d46a 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/PermissionManager.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/api/PermissionManager.java
@@ -27,6 +27,6 @@ public interface PermissionManager {
public List getSubjectPermissions(String subjectId) throws Exception;
- public void createPremission(String objectId, String subjectId) throws Exception;
+ public void createPermission(String objectId, String subjectId) throws Exception;
}
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/ProfileMBeanImpl.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/ProfileMBeanImpl.java
index 048e53d0..f35c7fb7 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/ProfileMBeanImpl.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/ProfileMBeanImpl.java
@@ -30,6 +30,7 @@ import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ru.entaxy.esb.platform.base.management.core.api.EntaxyRuntimeTyped;
import ru.entaxy.esb.platform.base.management.core.utils.BundleAwareMBeanImpl;
import ru.entaxy.esb.platform.core.management.profile.ProfileMBean;
import ru.entaxy.esb.platform.core.management.profile.impl.helper.Helpers;
@@ -37,6 +38,8 @@ import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import ru.entaxy.esb.system.jpa.entity.System;
import ru.entaxy.platform.base.support.CommonUtils;
+// @TODO move string to constant
+@EntaxyRuntimeTyped(name = "entaxy.runtime.profile")
public class ProfileMBeanImpl extends BundleAwareMBeanImpl implements ProfileMBean {
private static final Logger log = LoggerFactory.getLogger(ProfileMBeanImpl.class);
@@ -88,8 +91,8 @@ public class ProfileMBeanImpl extends BundleAwareMBeanImpl paramaters) throws Exception {
- this.helpers.connectorHelper.addConnector(getName(), connectorFactoryId, paramaters);
+ public void addConnector(String connectorFactoryId, Map parameters) throws Exception {
+ this.helpers.connectorHelper.addConnector(getName(), connectorFactoryId, parameters);
}
@Override
@@ -129,12 +132,12 @@ public class ProfileMBeanImpl extends BundleAwareMBeanImpl paramaters)
+ public void addConnector(String idOrName, String connectorFactoryId, Map parameters)
throws Exception {
throw new OperationNotSupportedException(EXPLANATION);
}
@@ -95,9 +95,9 @@ public class ConnectorHelperImpl implements ConnectorHelper {
@Override
- public void addConnector(String idOrName, String connectorFactoryId, Map paramaters)
+ public void addConnector(String idOrName, String connectorFactoryId, Map parameters)
throws Exception {
- getEffectiveConnectorManager().addConnector(idOrName, connectorFactoryId, paramaters);
+ getEffectiveConnectorManager().addConnector(idOrName, connectorFactoryId, parameters);
}
@Override
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/connector/ConnectorMBeanImpl.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/connector/ConnectorMBeanImpl.java
index 19965658..b43e208a 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/connector/ConnectorMBeanImpl.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/connector/ConnectorMBeanImpl.java
@@ -23,10 +23,13 @@ import javax.management.NotCompliantMBeanException;
import org.osgi.framework.BundleContext;
+import ru.entaxy.esb.platform.base.management.core.api.EntaxyRuntimeTyped;
import ru.entaxy.esb.platform.base.management.core.utils.BundleAwareMBeanImpl;
import ru.entaxy.esb.platform.core.management.profile.ConnectorMBean;
import ru.entaxy.esb.platform.core.management.profile.impl.helper.Helpers;
+//@TODO move string to constant
+@EntaxyRuntimeTyped(name = "entaxy.runtime.connector")
public class ConnectorMBeanImpl extends BundleAwareMBeanImpl implements ConnectorMBean {
protected Helpers helpers;
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/permission/PermissionHelperImpl.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/permission/PermissionHelperImpl.java
index 3d882ab5..7edcf6e9 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/permission/PermissionHelperImpl.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/permission/PermissionHelperImpl.java
@@ -59,7 +59,7 @@ public class PermissionHelperImpl implements PermissionHelper {
throw new OperationNotSupportedException(EXPLANATION); }
@Override
- public void createPremission(String objectId, String subjectId) throws Exception {
+ public void createPermission(String objectId, String subjectId) throws Exception {
throw new OperationNotSupportedException(EXPLANATION); }
};
}
@@ -96,8 +96,8 @@ public class PermissionHelperImpl implements PermissionHelper {
}
@Override
- public void createPremission(String objectId, String subjectId) throws Exception {
- getEffectivePermissionManager().createPremission(objectId, subjectId);
+ public void createPermission(String objectId, String subjectId) throws Exception {
+ getEffectivePermissionManager().createPermission(objectId, subjectId);
}
}
diff --git a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/route/DefaultRouteMBeanImpl.java b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/route/DefaultRouteMBeanImpl.java
index e7399497..a1c368e5 100644
--- a/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/route/DefaultRouteMBeanImpl.java
+++ b/platform/runtime/core/management/profile-management/src/main/java/ru/entaxy/esb/platform/core/management/profile/impl/route/DefaultRouteMBeanImpl.java
@@ -23,9 +23,12 @@ import javax.management.NotCompliantMBeanException;
import org.osgi.framework.BundleContext;
+import ru.entaxy.esb.platform.base.management.core.api.EntaxyRuntimeTyped;
import ru.entaxy.esb.platform.base.management.core.utils.BundleAwareMBeanImpl;
import ru.entaxy.esb.platform.core.management.profile.DefaultRouteMBean;
+//@TODO move string to constant
+@EntaxyRuntimeTyped(name = "entaxy.runtime.default-route")
public class DefaultRouteMBeanImpl extends BundleAwareMBeanImpl implements DefaultRouteMBean {
diff --git a/platform/runtime/core/object-producing/LICENSE.txt b/platform/runtime/core/object-producing/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/core/object-producing/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/core/object-producing/object-producer-api/LICENSE.txt b/platform/runtime/core/object-producing/object-producer-api/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/core/object-producing/object-producer-api/pom.xml b/platform/runtime/core/object-producing/object-producer-api/pom.xml
new file mode 100644
index 00000000..fd1ae280
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/pom.xml
@@ -0,0 +1,18 @@
+
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime.core
+ object-producing
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.core.object-producing
+ object-producer-api
+ bundle
+ ENTAXY :: PLATFORM :: CORE :: OBJECT PRODUCING :: PRODUCER API
+ ENTAXY :: PLATFORM :: CORE :: OBJECT PRODUCING :: PRODUCER API
+
+
+ ru.entaxy.platform.core.producer.api
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducer.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducer.java
new file mode 100644
index 00000000..7aa7b5f3
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducer.java
@@ -0,0 +1,46 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import java.util.List;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+
+public interface EntaxyProducer {
+
+ public interface EntaxyProducerListener {
+
+ public void factoryAdded(String factoryId, String factoryType, EntaxyProducer producer);
+ public void factoryRemoved(String factoryId, String factoryType, EntaxyProducer producer);
+
+ }
+
+ public void addListener(EntaxyProducerListener listener);
+ public void removeListener(EntaxyProducerListener listener);
+
+ public String getProducerId();
+
+ public List getSupportedTypes();
+
+ public List getAllFactories();
+ public List getFactoriesForType(String factoryType);
+ public EntaxyFactory getFactoryById(String factoryId);
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducerService.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducerService.java
new file mode 100644
index 00000000..342bc68b
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducerService.java
@@ -0,0 +1,58 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import java.util.List;
+
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+
+public interface EntaxyProducerService {
+
+ public static interface INSTRUCTIONS {
+
+ public static final String PRINT_OUTPUT = "printOutput";
+ public static final String SKIP = "skip";
+
+ public static interface ARTIFACT {
+
+ public static final String VERSION = "artifact.version";
+ public static final String TIMESTAMP = "artifact.timestamp";
+ public static final String VERSION_POLICY = "artifact.version.policy";
+
+ }
+
+ };
+
+ public ProducerResult produce(String configuration);
+ public ProducerResult produce(JsonObject configuration);
+
+ public ProducerResult produce(String configuration, String instructions);
+ public ProducerResult produce(JsonObject configuration, String instructions);
+
+ public List getAllProducers();
+ public EntaxyProducer getProducerForType(String type);
+ public EntaxyFactory findFactoryById(String factoryId);
+
+ public List getAvailableCommands();
+ public void registerCommand(ProducingCommandExecutor commandExecutor);
+ public ProducingCommandExecutor getCommandById(String id);
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducerUtils.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducerUtils.java
new file mode 100644
index 00000000..7b794aaf
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyProducerUtils.java
@@ -0,0 +1,89 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-api
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+public class EntaxyProducerUtils {
+
+ protected static Gson sharedGson = new Gson();
+
+ protected static class InstructionsItemBuilder {
+
+ protected JsonObject instructionsJson;
+
+ protected InstructionsItemBuilder(JsonObject jsonObject) {
+ this.instructionsJson = jsonObject;
+ }
+
+ }
+
+ public static class InstructionsBuilder extends InstructionsItemBuilder {
+
+ protected InstructionsBuilder(JsonObject jsonObject) {
+ super(jsonObject);
+ }
+
+ public CommandBuilder command(String commandName) {
+ if (!instructionsJson.has(commandName))
+ instructionsJson.add(commandName, new JsonObject());
+ return new CommandBuilder(instructionsJson, instructionsJson.get(commandName).getAsJsonObject());
+
+ }
+
+ public CommandBuilder any() {
+ return this.command("*");
+ }
+
+ public JsonObject getInstructions() {
+ return this.instructionsJson;
+ }
+
+ public String getInstructionsString() {
+ return getInstructions().toString();
+ }
+ }
+
+ public static class CommandBuilder extends InstructionsBuilder {
+
+ protected JsonObject commandJson;
+
+ protected CommandBuilder(JsonObject instructionsObject, JsonObject commandObject) {
+ super(instructionsObject);
+ commandJson = commandObject;
+ }
+
+ public CommandBuilder set(String name, Object value) {
+ this.commandJson.remove(name);
+ this.commandJson.add(name, sharedGson.toJsonTree(value));
+ return this;
+ }
+
+ }
+
+ public static InstructionsBuilder instructions() {
+ return instructions(new JsonObject());
+ }
+
+ public static InstructionsBuilder instructions(JsonObject jsonObject) {
+ return new InstructionsBuilder(jsonObject);
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyWrappedFactory.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyWrappedFactory.java
new file mode 100644
index 00000000..d31247e2
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/EntaxyWrappedFactory.java
@@ -0,0 +1,28 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+
+public interface EntaxyWrappedFactory extends EntaxyFactory {
+
+ public EntaxyFactory getOrigin();
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ExecutionPlan.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ExecutionPlan.java
new file mode 100644
index 00000000..18328d63
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ExecutionPlan.java
@@ -0,0 +1,172 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.core.producer.api.ExecutionPlan.ExecutionPlanUpdate.OPERATIONS;
+
+public class ExecutionPlan implements Iterable {
+
+ public List tasks = new ArrayList<>();
+
+ public ExecutionPlan(List tasks) {
+ this.tasks = tasks;
+ }
+
+ protected Iterator currentIterator;
+
+ protected ExecutionPlanIterator iterator = null;
+
+ @Override
+ public Iterator iterator() {
+ this.currentIterator = this.tasks.listIterator();
+ if (this.iterator == null)
+ this.iterator = new ExecutionPlanIterator();
+ return this.iterator;
+ }
+
+ public List applyUpdate(ExecutionPlanUpdate planUpdate) throws Exception {
+ List result = new LinkedList<>();
+
+ for (ExecutionPlanUpdate.ExecutionPlanUpdateRecord record: planUpdate.records) {
+ if (ExecutionPlanUpdate.OPERATIONS.RESET.equals(record.operation)) {
+ String target = record.target;
+ reset(target);
+ result.add(OPERATIONS.RESET);
+ continue;
+ }
+ if (ExecutionPlanUpdate.OPERATIONS.UPDATE_INSTRUCTIONS.equals(record.operation)) {
+ String target = record.target;
+ synchronized (tasks) {
+ for (ExecutionTask task: tasks)
+ if (task.commandId.equals(target)) {
+ if ((task.instructions == null) || task.instructions.isEmpty())
+ task.instructions = new HashMap<>();
+ task.instructions.putAll(record.values);
+ result.add(OPERATIONS.UPDATE_INSTRUCTIONS);
+ continue;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ protected void reset(String commandId) throws Exception {
+ synchronized (tasks) {
+ if (CommonUtils.isValid(commandId)) {
+ for (int i=0; i getCurrentIterator(){
+ return this.currentIterator;
+ }
+
+ protected class ExecutionPlanIterator implements Iterator{
+
+ @Override
+ public boolean hasNext() {
+ return ExecutionPlan.this.getCurrentIterator().hasNext();
+ }
+
+ @Override
+ public ExecutionTask next() {
+ return ExecutionPlan.this.getCurrentIterator().next();
+ }
+
+ }
+
+ public static class ExecutionPlanUpdate {
+
+ public static enum OPERATIONS {
+ RESET,
+ UPDATE_INSTRUCTIONS
+ }
+
+ protected List records = new LinkedList<>();
+
+ public static class ExecutionPlanUpdateRecord {
+
+ protected ExecutionPlanUpdate planUpdate;
+
+ protected OPERATIONS operation;
+
+ protected String target;
+
+ protected Map values = new LinkedHashMap<>();
+
+ protected ExecutionPlanUpdateRecord(ExecutionPlanUpdate planUpdate) {
+ this.planUpdate = planUpdate;
+ }
+
+ public ExecutionPlanUpdateRecord target(String value) {
+ this.target = value;
+ return this;
+ }
+
+ public ExecutionPlanUpdateRecord value(String name, Object value) {
+ this.values.put(name, value);
+ return this;
+ }
+
+ public ExecutionPlanUpdate complete() {
+ return this.planUpdate;
+ }
+ }
+
+ public static ExecutionPlanUpdate create() {
+ return new ExecutionPlanUpdate();
+ }
+
+ public ExecutionPlanUpdateRecord reset() {
+ ExecutionPlanUpdateRecord record = new ExecutionPlanUpdateRecord(this);
+ record.operation = OPERATIONS.RESET;
+ this.records.add(record);
+ return record;
+ }
+
+ public ExecutionPlanUpdateRecord updateInstructions() {
+ ExecutionPlanUpdateRecord record = new ExecutionPlanUpdateRecord(this);
+ record.operation = OPERATIONS.UPDATE_INSTRUCTIONS;
+ this.records.add(record);
+ return record;
+ }
+
+
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ExecutionTask.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ExecutionTask.java
new file mode 100644
index 00000000..d2c0d702
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ExecutionTask.java
@@ -0,0 +1,42 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExecutionTask {
+
+ public String commandId;
+ public ProducingCommandExecutor executor;
+ public Map instructions = new HashMap<>();
+ public List dependsOn = new ArrayList<>();
+
+ public ExecutionTask() {
+ super();
+ }
+
+ public ExecutionTask(String id) {
+ super();
+ this.commandId = id;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ProducerResult.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ProducerResult.java
new file mode 100644
index 00000000..9aad2d68
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ProducerResult.java
@@ -0,0 +1,124 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.core.producer.api.ExecutionPlan.ExecutionPlanUpdate;
+
+public class ProducerResult {
+
+ private static final Logger log = LoggerFactory.getLogger(ProducerResult.class);
+
+ public static class CommandResult {
+
+ public String commandId;
+ public boolean result = true;
+ public boolean skipped = false;
+ public List exceptions = new ArrayList<>();
+ public Object resultObject = null;
+ public ExecutionPlanUpdate planUpdate = null;
+
+ public CommandResult(String id) {
+ this.commandId = id;
+ }
+
+ public ProducerResult.CommandResult result(boolean resultValue) {
+ this.result = resultValue;
+ return this;
+ };
+
+ public ProducerResult.CommandResult resultObject(Object resultObjectValue) {
+ this.resultObject = resultObjectValue;
+ return this;
+ };
+
+ public ProducerResult.CommandResult exception(Exception exceptionValue) {
+ this.exceptions.add(exceptionValue);
+ return this;
+ };
+ }
+
+ public static ProducerResult createFailed(Exception e) {
+ ProducerResult result = new ProducerResult();
+ result.commandResult("#").exception(e).result(false);
+ return result;
+ }
+
+ protected List commandResults = new LinkedList<>();
+
+
+ public Object getLastObject() {
+ if (commandResults.isEmpty())
+ return null;
+ return commandResults.get(commandResults.size()-1).resultObject;
+ }
+
+ public CommandResult getLastCommandResult() {
+ if (commandResults.isEmpty())
+ return null;
+ return commandResults.get(commandResults.size()-1);
+ }
+
+ public Map> getAllExceptions(){
+ Map> result = new LinkedHashMap<>();
+ for (CommandResult cr: commandResults)
+ if (!cr.exceptions.isEmpty())
+ result.put(cr.commandId, cr.exceptions);
+ return result;
+ }
+
+ public List getCommandResults() {
+ return commandResults;
+ }
+
+ public T findResultObject(Class clazz){
+ log.debug("findResultObject : " + clazz.getName());
+ ListIterator listIterator = commandResults.listIterator(commandResults.size());
+ while (listIterator.hasPrevious()) {
+ CommandResult cr = listIterator.previous();
+ log.debug("Inspecting : " + cr.commandId);
+ if ((cr.resultObject != null) && (clazz.isInstance(cr.resultObject))) {
+ log.debug("... found");
+ return clazz.cast(cr.resultObject);
+ }
+ log.debug("... not found");
+ }
+ return null;
+ }
+
+ public CommandResult commandResult(String id) {
+ CommandResult commandResult = new CommandResult(id);
+ this.commandResults.add(commandResult);
+ return commandResult;
+ }
+
+ public void addCommandResult(CommandResult commandResult) {
+ this.commandResults.add(commandResult);
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ProducingCommandExecutor.java b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ProducingCommandExecutor.java
new file mode 100644
index 00000000..b0bcac56
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-api/src/main/java/ru/entaxy/platform/core/producer/api/ProducingCommandExecutor.java
@@ -0,0 +1,32 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.api;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ProducingCommandExecutor {
+ public String getId();
+ public List getRequiredPredecessors();
+ public List getDescendants();
+ public List> getAcceptedInputClasses();
+ public List> getProducedOutputClasses();
+ public ProducerResult execute(ProducerResult currentResult, Map parameters);
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/LICENSE.txt b/platform/runtime/core/object-producing/object-producer-core/LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/platform/runtime/core/object-producing/object-producer-core/pom.xml b/platform/runtime/core/object-producing/object-producer-core/pom.xml
new file mode 100644
index 00000000..e60c1a39
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/pom.xml
@@ -0,0 +1,32 @@
+
+ 4.0.0
+
+ ru.entaxy.esb.platform.runtime.core
+ object-producing
+ 1.8.2
+
+ ru.entaxy.esb.platform.runtime.core.object-producing
+ object-producer-core
+ bundle
+ ENTAXY :: PLATFORM :: CORE :: OBJECT PRODUCING :: PRODUCER CORE
+ ENTAXY :: PLATFORM :: CORE :: OBJECT PRODUCING :: PRODUCER CORE
+
+
+ ru.entaxy.platform.core.producer.*
+
+
+
+
+
+ ru.entaxy.esb.platform.runtime.core.object-producing
+
+ object-producer-api
+ ${project.version}
+
+
+ ru.entaxy.esb.platform.runtime.core
+ artifact-management
+ ${project.version}
+
+
+
\ No newline at end of file
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/AbstractCommandExecutor.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/AbstractCommandExecutor.java
new file mode 100644
index 00000000..e15d3acf
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/AbstractCommandExecutor.java
@@ -0,0 +1,162 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.api.ProducingCommandExecutor;
+
+public abstract class AbstractCommandExecutor implements ProducingCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractCommandExecutor.class);
+
+ public static String SKIP_INSTRUSTION = "skip";
+ public static String PRINT_OUTPUT_INSTRUSTION = "printOutput";
+
+ protected EntaxyProducerService entaxyProducerService;
+
+ protected String id;
+ protected List requiredPredecessors = new ArrayList<>();
+ protected List descendants = new ArrayList<>();
+ protected List> acceptedInputClasses = new ArrayList<>();
+ protected List> producedOutputClasses = new ArrayList<>();
+
+ protected boolean isPrintOutput = false;
+
+ protected Map instructions;
+
+ protected AbstractCommandExecutor(EntaxyProducerService entaxyProducerService) {
+ this.entaxyProducerService = entaxyProducerService;
+ if (this.getClass().isAnnotationPresent(CommandExecutor.class)) {
+ CommandExecutor commandExecutorAnnotation = this.getClass().getAnnotation(CommandExecutor.class);
+ this.id = commandExecutorAnnotation.id();
+ this.requiredPredecessors = Arrays.asList(commandExecutorAnnotation.predecessors());
+ this.descendants = Arrays.asList(commandExecutorAnnotation.descendants());
+ this.acceptedInputClasses = Arrays.asList(commandExecutorAnnotation.inputs());
+ this.producedOutputClasses = Arrays.asList(commandExecutorAnnotation.outputs());
+ }
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public List getRequiredPredecessors() {
+ return requiredPredecessors;
+ }
+
+ public void setRequiredPredecessors(List requiredPredecessors) {
+ this.requiredPredecessors = requiredPredecessors;
+ }
+
+ @Override
+ public List getDescendants() {
+ return descendants;
+ }
+
+ public void setDescendants(List descendants) {
+ this.descendants = descendants;
+ }
+
+ @Override
+ public List> getAcceptedInputClasses() {
+ return acceptedInputClasses;
+ }
+
+ public void setAcceptedInputClasses(List> acceptedInputClasses) {
+ this.acceptedInputClasses = acceptedInputClasses;
+ }
+
+ @Override
+ public List> getProducedOutputClasses() {
+ return this.producedOutputClasses;
+ }
+
+ public void setProducedOutputClasses(List> producedOutputClasses) {
+ this.producedOutputClasses = producedOutputClasses;
+ }
+
+ @Override
+ public ProducerResult execute(ProducerResult currentResult, Map instructions) {
+ CommandResult cr = new CommandResult(getId());
+ this.instructions = instructions;
+ setPrintOutput(instructions);
+ if (isSkipped(instructions))
+ cr.skipped = true;
+ else
+ try {
+ cr.result = doExecute(currentResult, cr, instructions);
+ } catch (Exception e) {
+ log.error("Error executing [" + getId() + "]", e);
+ cr.exception(e).result(false);
+ }
+ currentResult.addCommandResult(cr);
+ return currentResult;
+ }
+
+ protected void setPrintOutput(Map parameters) {
+ if (parameters.containsKey(PRINT_OUTPUT_INSTRUSTION)) {
+ Object val = parameters.get(PRINT_OUTPUT_INSTRUSTION);
+ if (val == null)
+ return;
+ if (val instanceof Boolean)
+ this.isPrintOutput = (Boolean)val;
+ }
+ }
+
+ protected void printOutput(String message) {
+ if (this.isPrintOutput)
+ // OUTPUT TO CONSOLE
+ System.out.println(message);
+ }
+
+ protected boolean isSkipped(Map parameters) {
+ if (!parameters.containsKey(SKIP_INSTRUSTION))
+ return false;
+ Object obj = parameters.get(SKIP_INSTRUSTION);
+ if (obj instanceof Boolean)
+ return (Boolean)obj;
+ if (obj instanceof String)
+ return "true".equalsIgnoreCase((String)obj);
+ if (obj instanceof Number)
+ return ((Number)obj).intValue() > 0;
+ return false;
+ }
+
+ protected abstract boolean doExecute(ProducerResult currentResult
+ , CommandResult commandResult
+ , Map instructions) throws Exception;
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/CommandExecutor.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/CommandExecutor.java
new file mode 100644
index 00000000..6899e9d8
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/CommandExecutor.java
@@ -0,0 +1,35 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CommandExecutor {
+ String id();
+ String[] predecessors() default {};
+ String[] descendants() default {};
+ Class>[] inputs() default {};
+ Class>[] outputs() default {};
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/CommandInstructions.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/CommandInstructions.java
new file mode 100644
index 00000000..a51b08e4
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/CommandInstructions.java
@@ -0,0 +1,86 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CommandInstructions {
+
+ protected Map instructionsMap = new HashMap<>();
+
+ public CommandInstructions() {
+ super();
+ }
+
+ public CommandInstructions(Map instructionsMap) {
+ super();
+ load(instructionsMap);
+ }
+
+ public void load(Map instructionsMap) {
+ this.instructionsMap = instructionsMap;
+ }
+
+ public boolean has(String name) {
+ return this.instructionsMap.containsKey(name);
+ }
+
+ public Boolean getBoolean(String name) {
+ if (!this.has(name))
+ return null;
+ Object value = this.instructionsMap.get(name);
+
+ if (value instanceof Boolean)
+ return (Boolean)value;
+
+ if (value instanceof String)
+ return "true".equals(((String)value).toLowerCase());
+
+ if (value instanceof Number)
+ return ((Number)value).longValue() > 0;
+
+ if (value instanceof Long)
+ return ((Long)value).longValue() > 0;
+
+ return value!=null;
+ }
+
+ public Object get(String name) {
+ return this.instructionsMap.get(name);
+ }
+
+ public String getString(String name) {
+ if (!has(name))
+ return null;
+ Object value = instructionsMap.get(name);
+ return value!=null?value.toString():"";
+ }
+
+ public Long getLong(String name) {
+ if (!has(name))
+ return null;
+ Object value = instructionsMap.get(name);
+ if (value instanceof Number)
+ return ((Number)value).longValue();
+ return (long)-1;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/ProducingExecutor.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/ProducingExecutor.java
new file mode 100644
index 00000000..f8bfd86c
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/ProducingExecutor.java
@@ -0,0 +1,209 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.DependencySorter;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ExecutionPlan;
+import ru.entaxy.platform.core.producer.api.ExecutionPlan.ExecutionPlanUpdate;
+import ru.entaxy.platform.core.producer.api.ExecutionPlan.ExecutionPlanUpdate.OPERATIONS;
+import ru.entaxy.platform.core.producer.api.ExecutionTask;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+
+public class ProducingExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(ProducingExecutor.class);
+
+ protected static final String DEFAULT_EXECUTION_PLAN = "{'validate':{}}";
+
+ protected static final String ANY_COMMAND = "*";
+
+ protected JsonObject configuration;
+ protected EntaxyProducerService producerService;
+
+ protected JsonObject executionPlanJSON = JSONUtils.getJsonRootObject(DEFAULT_EXECUTION_PLAN);
+
+ protected ExecutionPlan executionPlan = null;
+
+ public ProducingExecutor(JsonObject configuration, String buildInstructions
+ , EntaxyProducerService producerService) throws Exception {
+ this.configuration = configuration;
+ this.producerService = producerService;
+ if (CommonUtils.isValid(buildInstructions)) {
+ executionPlanJSON = JSONUtils.getJsonRootObject(buildInstructions);
+ if (executionPlanJSON.entrySet().isEmpty())
+ executionPlanJSON = JSONUtils.getJsonRootObject(DEFAULT_EXECUTION_PLAN);
+ }
+ buildPlan();
+ }
+
+ protected ExecutionTask createExecutionTask(String id, Map parameters) {
+ ExecutionTask result = new ExecutionTask();
+
+ result.commandId = id;
+ result.instructions = parameters;
+ result.executor = producerService.getCommandById(result.commandId);
+
+ return result;
+ }
+
+ protected ExecutionTask createExecutionTask(Map taskMap, String id, Map commandInstructions) {
+ if (!taskMap.containsKey(id))
+ taskMap.put(id, new ExecutionTask(id));
+ ExecutionTask result = taskMap.get(id);
+ result.instructions = commandInstructions;
+ result.executor = producerService.getCommandById(result.commandId);
+
+ return result;
+
+ }
+
+ protected void createDependency(Map taskMap, String masterId, String slaveId) {
+ taskMap.get(slaveId).dependsOn.add(taskMap.get(masterId));
+ }
+
+ protected void buildPlan() throws Exception {
+ log.debug("building plan for execution on: \n" + configuration.toString());
+ log.debug("execution plan: \n" + executionPlanJSON.toString());
+
+ Map taskMap = new HashMap<>();
+
+ Map anyCommandInstructions = new HashMap<>();
+ if (executionPlanJSON.has(ANY_COMMAND))
+ anyCommandInstructions = JSONUtils.element2map(executionPlanJSON.get(ANY_COMMAND));
+
+ List neededCommands = new ArrayList<>();
+ for (String id: executionPlanJSON.keySet()) {
+ if (ANY_COMMAND.equals(id))
+ continue;
+ JsonElement jsonElement = executionPlanJSON.get(id);
+ Map commandInstructions = new HashMap<>(anyCommandInstructions);
+ commandInstructions.putAll(JSONUtils.element2map(jsonElement));
+ neededCommands.add(id);
+ if (createExecutionTask(taskMap, id, commandInstructions).executor == null) {
+ log.error("Command [{}] not found", id);
+ throw new Exception("Command not found: " + id);
+ }
+ }
+
+ List commandsToCheck = List.copyOf(neededCommands);
+ List newCommandsToCheck = new ArrayList<>();
+
+ // add required commands
+
+ while (!commandsToCheck.isEmpty()) {
+ newCommandsToCheck.clear();
+ for (String command: commandsToCheck) {
+ log.debug("Checking command [{}]", command);
+ for (String s: taskMap.get(command).executor.getRequiredPredecessors()) {
+ if (!neededCommands.contains(s)) {
+ log.debug("Adding command [{}]", s);
+ newCommandsToCheck.add(s);
+ neededCommands.add(s);
+ if (createExecutionTask(taskMap, s, anyCommandInstructions).executor == null) {
+ log.error("Command [{}] not found", s);
+ throw new Exception("Command not found: " + s);
+ }
+ }
+ createDependency(taskMap, s, command);
+ }
+ }
+ commandsToCheck = List.copyOf(newCommandsToCheck);
+ }
+
+ // create backward dependencies by descendants
+ for (String s: taskMap.keySet()) {
+ for (String descendant: taskMap.get(s).executor.getDescendants()) {
+ if (taskMap.containsKey(descendant))
+ createDependency(taskMap, s, descendant);
+ }
+ }
+
+
+ // arrange commands
+
+ executionPlan = new ExecutionPlan(new LinkedList<>(taskMap.values()));
+ List sorted = DependencySorter.getSortedList(
+ executionPlan.tasks,
+ new DependencySorter.DependencyProvider() {
+
+ @Override
+ public List getDependencies(ExecutionTask inspectedObject) {
+ return inspectedObject.dependsOn;
+ }
+
+ });
+ executionPlan.tasks = sorted;
+
+ }
+
+ public ProducerResult execute() {
+
+ ProducerResult producerResult = new ProducerResult();
+
+ producerResult.commandResult("#plan").result(true).resultObject(executionPlan);
+ producerResult.commandResult("#init").result(true).resultObject(configuration);
+
+ return execute(producerResult);
+
+ }
+
+ protected ProducerResult execute(ProducerResult producerResult) {
+
+ Iterator taskIterator = executionPlan.iterator();
+
+ while (taskIterator.hasNext()) {
+ ExecutionTask task = taskIterator.next();
+ task.executor.execute(producerResult, task.instructions);
+ CommandResult cr = producerResult.getLastCommandResult();
+ if (cr.planUpdate != null) {
+ try {
+ log.debug("Applying plan update");
+ List result = executionPlan.applyUpdate(cr.planUpdate);
+ producerResult.commandResult("#planUpdate").result(true).resultObject(cr.planUpdate);
+ if (result.contains(OPERATIONS.RESET))
+ producerResult.commandResult("#reset").result(true).resultObject(cr.planUpdate);
+ } catch (Exception e) {
+ log.error("Error applying plan update", e);
+ producerResult.commandResult("#planUpdate").result(false).resultObject(cr.planUpdate).exception(e);
+ }
+ }
+ }
+
+ return producerResult;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Analyze.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Analyze.java
new file mode 100644
index 00000000..70ac5dd5
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Analyze.java
@@ -0,0 +1,79 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectRef;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+
+@CommandExecutor(id = "analyze", inputs = {JsonObject.class}, predecessors = {})
+public class Analyze extends AbstractCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(Analyze.class);
+
+ public Analyze(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+ log.info("Executing command [{}]", getId());
+
+ JsonObject jo = currentResult.findResultObject(JsonObject.class);
+
+ printOutput("\n\n\t== ANALYZE == \n\n");
+ printOutput("\n\tIncoming JSON ::\n\n");
+ printOutput(jo.toString());
+
+ ObjectModel om = new ObjectModel();
+ om.load(jo);
+ om.checkRefs();
+
+ printOutput("\n\tObjectModel ::\n\n");
+ for (FactoredObject fo: om.objects)
+ printOutput("Object :: [" + fo.getObjectId() + "/" + fo.factoryId + ":" + fo.getObjectType() + "]");
+ for (FactoredObjectRef fo: om.refs)
+ printOutput("Reference :: [" + fo.definedIn.getObjectId() + " -> " + fo.getTargetId()
+ + "; isLink=" + fo.isLink()
+ + "; isExternal=" + fo.isExternal()
+ + "]");
+
+ commandResult.resultObject(om);
+
+ printOutput("\n\tOutgoing JSON ::\n\n");
+ printOutput(om.getJsonCurrent().toString());
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Build.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Build.java
new file mode 100644
index 00000000..760d439c
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Build.java
@@ -0,0 +1,151 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.core.artifact.Artifact;
+import ru.entaxy.platform.core.artifact.ArtifactManifest;
+import ru.entaxy.platform.core.artifact.Artifacts;
+import ru.entaxy.platform.core.artifact.Manifested;
+import ru.entaxy.platform.core.artifact.capabilities.ManifestCapabilityHelper;
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+import ru.entaxy.platform.base.objects.EntaxyObject.HEADERS;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.generationmodel.GeneratedHeaders;
+import ru.entaxy.platform.core.producer.executor.generationmodel.GeneratedList;
+import ru.entaxy.platform.core.producer.executor.support.ArtifactList;
+
+@CommandExecutor(id = "build", predecessors = {"generate"})
+public class Build extends AbstractCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(Build.class);
+
+ public Build(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+ printOutput("\n\t == BUILDING ==\n");
+ GeneratedList generated = currentResult.findResultObject(GeneratedList.class);
+ if (generated == null) {
+ log.info("Nothing to generate");
+ return true;
+ }
+
+ ArtifactList artifactList = new ArtifactList();
+
+ for (Generated g: generated) {
+ if (g == null)
+ continue;
+ Artifact artifact = Artifacts.fromGenerated(g);
+ if ((artifact == null) || Artifact.ARTIFACT_CATEGORY_UNKNOWN.equals(artifact.getCategory())
+ || !CommonUtils.isValid(artifact.getCategory())) {
+ log.info("Artifact is not buildable");
+ continue;
+ }
+ log.info("Built artifact of category [{}]", artifact.getCategory());
+ Map headers = GeneratedHeaders.getHeaders(g.getProperties()).getAsStringMap();
+
+ String mainObjectValue = headers.get(HEADERS.MAIN_OBJECT);
+ if (!CommonUtils.isValid(mainObjectValue))
+ throw new Exception("Main object not found");
+ String[] mainObjectData = mainObjectValue.split(":");
+ if (mainObjectData.length<2)
+ throw new Exception("Main object not complete: [" + mainObjectValue + "]");
+
+ String versionPolicy = g.getProperties().getOrDefault(
+ EntaxyProducerService.INSTRUCTIONS.ARTIFACT.VERSION_POLICY,
+ instructions.getOrDefault(
+ EntaxyProducerService.INSTRUCTIONS.ARTIFACT.VERSION_POLICY
+ , ""))
+ .toString();
+ String timestamp = g.getProperties().getOrDefault(
+ EntaxyProducerService.INSTRUCTIONS.ARTIFACT.TIMESTAMP,
+ instructions.getOrDefault(
+ EntaxyProducerService.INSTRUCTIONS.ARTIFACT.TIMESTAMP
+ , ""))
+ .toString();
+ artifact.getCoordinates()
+ .groupId(mainObjectData[1])
+ .artifactId(mainObjectData[0])
+ .version("1")
+ .versionPolicy(versionPolicy)
+ .timestamp(timestamp);
+
+ if (artifact instanceof Manifested) {
+ ArtifactManifest manifest = ((Manifested)artifact).getManifest();
+ manifest.getCustomAttributes().putAll(headers);
+
+ // Generate provided capabilities for every included object
+ ManifestCapabilityHelper helper = new ManifestCapabilityHelper(manifest);
+
+ String objectsValue = headers.getOrDefault(HEADERS.GENERATED_OBJECTS, "");
+ if (CommonUtils.isValid(objectsValue)) {
+ String[] objects = objectsValue.split(",");
+
+ for (int i=0; i attributes = null;
+ if (g.getProperties().containsKey(FIELDS.FIELDS_TO_PUBLISH)) {
+ Object map = g.getProperties().get(FIELDS.FIELDS_TO_PUBLISH);
+ if (map != null) {
+ attributes = (Map)((Map)map).get(objectId);
+ }
+ }
+ helper.provideCapability(objectType).attributes(attributes);
+ }
+
+ helper.save();
+
+ }
+ }
+ artifact.getProperties().putAll(g.getProperties());
+ artifactList.add(artifact);
+ printOutput("\n\t == " + artifact.getCoordinates().toString() + " ==\n");
+ printOutput(new String(artifact.asByteArray()));
+ printOutput("\n\t == \n");
+ }
+
+ commandResult.resultObject(artifactList);
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Deploy.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Deploy.java
new file mode 100644
index 00000000..c51259d4
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Deploy.java
@@ -0,0 +1,79 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import ru.entaxy.platform.core.artifact.Artifact;
+import ru.entaxy.platform.core.artifact.DeployedArtifact;
+import ru.entaxy.platform.core.artifact.service.ArtifactService;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.support.ArtifactList;
+import ru.entaxy.platform.core.producer.executor.support.ArtifactsHelper;
+import ru.entaxy.platform.core.producer.executor.support.DeployedArtifactList;
+
+@CommandExecutor(id = "deploy", predecessors = {"build"})
+public class Deploy extends AbstractCommandExecutor {
+
+ public static final String DEPLOY_LOCAL_INSTRUCTION = "deployLocal";
+
+ public Deploy(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+
+ boolean deployLocal = false;
+
+ Object deployLocalValue = instructions.get(DEPLOY_LOCAL_INSTRUCTION);
+ if (deployLocalValue != null)
+ if (deployLocalValue instanceof Boolean)
+ deployLocal = (Boolean)deployLocalValue;
+
+ ArtifactList artifactList = currentResult.findResultObject(ArtifactList.class);
+ DeployedArtifactList deployedArtifactList = new DeployedArtifactList();
+
+ ArtifactService artifactService = ArtifactsHelper.getInstance().getArtifactService();
+
+ for (Artifact artifact: artifactList) {
+ DeployedArtifact da = deployLocal
+ ?artifactService.deployLocal(artifact)
+ :artifactService.deployShared(artifact);
+ deployedArtifactList.add(da);
+ }
+
+ printOutput("\n\n\t== DEPLOY ==\n");
+ printOutput("DEPLOYED: ["
+ + deployedArtifactList.stream().map(da->da.getLocation()).collect(Collectors.joining(","))
+ + "]");
+
+ commandResult.resultObject(deployedArtifactList);
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Enrich.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Enrich.java
new file mode 100644
index 00000000..90d68c4f
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Enrich.java
@@ -0,0 +1,548 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.CONFIGURATION.OUTPUTS;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.FieldInfo;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory.RefFieldInfo;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ExecutionPlan.ExecutionPlanUpdate;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectProxy;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectRef;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+import ru.entaxy.platform.core.producer.impl.FieldInfoImpl;
+import ru.entaxy.platform.core.producer.impl.RefFieldInfoImpl;
+
+@CommandExecutor(id = "enrich", predecessors = {"layout"})
+public class Enrich extends AbstractCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(Enrich.class);
+
+ public Enrich(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ // TODO Auto-generated constructor stub
+ }
+
+ // TODO move to FieldInfo
+ protected boolean isLookup(FieldInfo fi) {
+ if (fi.getJsonOrigin().has("lookup")) {
+ String lookup = fi.getJsonOrigin().get("lookup").getAsString();
+ return CommonUtils.isValid(lookup);
+ }
+ return false;
+ }
+
+ // TODO move to FieldInfo
+ public String getLookup(FieldInfo fi) {
+ return fi.getJsonOrigin().has("lookup")
+ ?fi.getJsonOrigin().get("lookup").getAsString()
+ :null;
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+
+ int count = 15;
+ if (!instructions.containsKey("_count")) {
+ instructions.put("_count", count);
+ }
+
+ if (instructions.get("_count") instanceof Integer)
+ count = (Integer)instructions.get("_count");
+ else if (instructions.get("_count") instanceof Number)
+ count = ((Number)instructions.get("_count")).intValue();
+ count--;
+
+ printOutput("\n\n\t== ENRICH == #" + count + " ==\n\n");
+
+ ObjectModel objectModel = currentResult.findResultObject(ObjectModel.class);
+ objectModel.startTracking();
+
+ JsonObject incomingJson = objectModel.getJsonCurrent().deepCopy();
+
+ Gson gson = new Gson();
+
+ // enrich type to ensure we can resolve refs
+
+ for (FactoredObject fo: objectModel.objects) {
+
+ // skip proxies
+ if (fo instanceof FactoredObjectProxy)
+ continue;
+
+ String factoryId = fo.factoryId;
+
+ EntaxyFactory factory = entaxyProducerService.findFactoryById(factoryId);
+ if (factory == null)
+ throw new Exception("Factory not found: [" + factoryId + "]");
+
+ String objectType = fo.getObjectType();
+ if (!CommonUtils.isValid(objectType)) {
+ fo.setObjectType(factory.getFactoryType());
+ objectModel.setDirty();
+ }
+ }
+
+ // enrich fields
+
+ for (FactoredObject fo: objectModel.objects) {
+
+ // skip proxies
+ if (fo instanceof FactoredObjectProxy)
+ continue;
+
+ String factoryId = fo.factoryId;
+
+ EntaxyFactory factory = entaxyProducerService.findFactoryById(factoryId);
+
+ List delayed = new LinkedList<>();
+
+ List processedFieldNames = new LinkedList<>();
+
+ JsonObject objectOrigin = fo.origin;
+
+ if (JSONUtils.setValue(objectOrigin, FIELDS.PROPERTIES, new JsonObject(), true)) {
+ printOutput("[DIRTY] CREATED 'properties' for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectModel.setDirty();
+ }
+
+ JsonObject objectProperties = objectOrigin.get(FIELDS.PROPERTIES).getAsJsonObject();
+
+ List factoryFields = factory.getFields(OUTPUTS.OUTPUT_TYPE_INIT);
+
+
+ for (FieldInfo fi: factoryFields) {
+
+ FieldInfo fieldInfo = fi;
+
+ log.info("\n ITERATING FOR FIELD: " + fi.getName() + "\n" + fi.getJsonOrigin());
+
+ if (FIELDS.OBJECT_ID.equals(fi.getName())
+ || FIELDS.OBJECT_TYPE.equals(fi.getName()))
+ continue;
+
+ // check if lookup
+ if (isLookup(fi)) {
+
+ String lookup = getLookup(fi);
+ log.info("\n LOOKUP FIELD: " + fi.getName() + " -> " + lookup);
+
+ // replace lookup with corresponding ref
+ Optional toLookupOpt = factoryFields.stream()
+ .filter(f -> lookup.equals(f.getName()))
+ .findFirst();
+ if (!toLookupOpt.isPresent()) {
+ // field to lookup not found
+ log.error("Factory configuration error: loooked up field [{}] referenced by [{}] not found in factory [{}]"
+ , lookup
+ , fi.getName()
+ , factory.getFactoryId());
+ continue;
+ }
+ FieldInfo toLookup = toLookupOpt.get();
+ RefFieldInfoImpl fieldInfoImpl = new RefFieldInfoImpl();
+ fieldInfoImpl.name(fi.getName())
+ .description(fi.getDescription())
+ .displayName(fi.getDisplayName())
+ .immutable(fi.isImmutable())
+ .required(fi.isRequired());
+ fieldInfoImpl.refField(
+ fi.getJsonOrigin().has(FIELDS.REF_FIELD)
+ ?fi.getJsonOrigin().get(FIELDS.REF_FIELD).getAsString()
+ :""
+ )
+ .refByValueOnly(true)
+ .backRef(false);
+ fieldInfoImpl.setConditional(fi.isConditional());
+ fieldInfoImpl.setCondition(fi.getCondition());
+ fieldInfoImpl.setRef(true);
+ fieldInfoImpl.setType(toLookup.getType());
+ JsonObject lookupJson = fi.getJsonOrigin().deepCopy();
+ JsonObject lookedUpJson = toLookup.getJsonOrigin();
+ for (Entry entry: lookedUpJson.entrySet()) {
+ if (lookupJson.has(entry.getKey()))
+ lookupJson.remove(entry.getKey());
+ lookupJson.add(entry.getKey(), entry.getValue());
+ }
+ fieldInfoImpl.setJsonOrigin(lookupJson);
+
+ log.info("\n LOOKUP FIELD JSON: \n" + lookupJson.toString());
+
+ fieldInfo = fieldInfoImpl;
+
+ if (!processedFieldNames.contains(lookup) || fi.isConditional()) {
+ delayed.add(fieldInfo);
+ continue;
+ }
+
+ }
+
+ // check if conditional
+ if (fi.isConditional()) {
+ delayed.add(fi);
+ continue;
+ }
+
+
+ processField(objectModel, fieldInfo, fo, gson);
+ processedFieldNames.add(fieldInfo.getName());
+ }
+
+ int delayedCount = 0;
+
+ while (delayedCount != delayed.size()) {
+ List toRemove = new ArrayList<>();
+
+ delayedCount = delayed.size();
+
+ for (FieldInfo fi: delayed) {
+
+ // first check conditionals
+
+ if (fi.isConditional()) {
+
+ String condition = fi.getCondition();
+ if (condition.startsWith("${"))
+ condition = condition.substring(2, condition.lastIndexOf("}"));
+
+
+ if (!objectProperties.has(condition))
+ continue;
+
+ Object conditionValue = JSONUtils.element2object(objectProperties.get(condition));
+ if (conditionValue == null) {
+ continue;
+ } else if (conditionValue instanceof String) {
+ if (!"true".equalsIgnoreCase((String)conditionValue)) {
+ toRemove.add(fi);
+ continue;
+ }
+ } else if (conditionValue instanceof Number) {
+ if (((Number)conditionValue).doubleValue()<=0) {
+ toRemove.add(fi);
+ continue;
+ }
+ } else if (conditionValue instanceof Boolean) {
+ if (!(Boolean)conditionValue) {
+ toRemove.add(fi);
+ continue;
+ }
+ }
+ }
+
+ // then check lookups
+ if (isLookup(fi)) {
+ if (!processedFieldNames.contains(getLookup(fi))) {
+ continue;
+ }
+ }
+
+ // we're still here so process
+ processField(objectModel, fi, fo, gson);
+ processedFieldNames.add(fi.getName());
+
+ }
+
+ delayed.removeAll(toRemove);
+ }
+
+ }
+
+
+
+
+ if (objectModel.stopTracking() && count>0) {
+
+ // remove ##embedded
+ for (FactoredObject fo: objectModel.objects)
+ fo.origin.remove(FactoredObject.EMBEDDED_FIELD);
+
+
+ commandResult.planUpdate = ExecutionPlanUpdate.create()
+// .updateInstructions().target("enrich").value("skip", true).complete()
+ .reset().target("analyze").complete();
+ }
+
+ instructions.put("_count", count);
+
+ JsonObject outgoingJson = objectModel.getJsonCurrent();
+
+ printOutput("\n== INCOMING JSON ==\n");
+ printOutput(incomingJson.toString());
+ printOutput("\n== OUTGOING JSON ==\n");
+ printOutput(outgoingJson.toString());
+
+ commandResult.resultObject(outgoingJson);
+
+ return true;
+ }
+
+ protected boolean processField(ObjectModel objectModel, FieldInfo fi, FactoredObject fo, Gson gson) {
+
+ log.info("\nPROCESSING FIELD: " + fi.getName());
+
+ if (fi.isRef()) {
+ log.info("\nPROCESSING REF: " + fi.getName());
+ return processRef(objectModel, (RefFieldInfo)fi, fo, gson);
+ }
+
+ boolean result = false;
+
+ JsonObject objectOrigin = fo.origin;
+ JsonObject objectProperties = objectOrigin.get(FIELDS.PROPERTIES).getAsJsonObject();
+
+ boolean exists = objectProperties.has(fi.getName());
+ if (!exists) {
+ if (fi.isRequired()) {
+ printOutput("[DIRTY] CREATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+
+ objectProperties.add(fi.getName(), fi.getJsonOrigin().get(FIELDS.DEFAULT_VALUE));
+ objectModel.setDirty();
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ protected boolean processRef(ObjectModel objectModel, RefFieldInfo fi, FactoredObject fo, Gson gson) {
+ boolean result = false;
+
+ JsonObject objectOrigin = fo.origin;
+ JsonObject objectProperties = objectOrigin.get(FIELDS.PROPERTIES).getAsJsonObject();
+
+ boolean exists = objectProperties.has(fi.getName());
+ if (!exists) {
+ if (fi.isRequired()) {
+
+ if (fi.isBackRef()) {
+ // it's a backRef, so we'll try to find object of the given type
+ // referencing current object
+ List candidates = fo.references.stream()
+ .filter(ref->!ref.isBackRef())
+ .map(ref->ref.definedIn)
+ .filter(obj->fi.getType().equals(obj.getObjectType()))
+ .collect(Collectors.toList());
+ if (candidates.size()>0) {
+ // we found candidates, so just add ref to first one
+ // no matter what object is there
+ // 'cause the ref being backRef won't be ever generated
+ FactoredObjectRef ref = new FactoredObjectRef(objectModel, candidates.get(0));
+ ref.definedIn = fo;
+ fo.embed(ref);
+ ref.setBackRef(true);
+ ref.setResolved(true);
+ printOutput("[DIRTY] CREATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectProperties.add(fi.getName(), ref.origin);
+ result = true;
+ } else {
+ // try to use default value
+ printOutput("[DIRTY] CREATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectProperties.add(fi.getName(), fi.getJsonOrigin().get(FIELDS.DEFAULT_VALUE));
+ objectModel.setDirty();
+ result = true;
+ }
+
+ } else {
+ // it's a direct ref
+
+ FactoredObject candidate = null;
+
+ // try to find by backRef
+ List backrefs = objectModel.refs.stream()
+ .filter(ref->
+ (ref.isBackRef()
+ && (ref.getTargetObject().equals(fo))
+ && (ref.definedIn.getObjectType().equals(fi.getType()))
+ )
+ )
+ .collect(Collectors.toList());
+ if (backrefs.size()>0) {
+ // we can use any
+ candidate = backrefs.get(0).definedIn;
+ } else {
+ // try to find objects of required type defined in current
+ List candidates = objectModel.objects
+ .stream()
+ .filter(
+ obj->((obj != fo) && (obj.getObjectType().equals(fi.getType())))
+ )
+ .collect(Collectors.toList());
+
+ // we can use the only one
+ if (candidates.size() == 1)
+ candidate = candidates.get(0);
+ else if (candidates.size()>1) {
+ // search for defined in current
+ candidates = candidates.stream().filter(c->c.isDefinedIn(fo))
+ .collect(Collectors.toList());
+ if (candidates.size()==1)
+ candidate = candidates.get(0);
+ }
+ }
+
+ if (candidate != null) {
+
+ FactoredObjectRef ref = new FactoredObjectRef(objectModel, candidate);
+ ref.definedIn = fo;
+ fo.embed(ref);
+ ref.origin.addProperty(FIELDS.IS_REF_BY_VALUE_ONLY, fi.isRefByValueOnly());
+ ref.origin.addProperty(FIELDS.REF_FIELD, fi.getRefField());
+ printOutput("[DIRTY] CREATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectProperties.add(fi.getName(), ref.origin);
+ objectModel.setDirty();
+ result = true;
+
+ } else {
+ /*
+ if (fi.getJsonOrigin().has(FIELDS.DEFAULT_VALUE)) {
+ printOutput("[DIRTY] CREATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectProperties.add(fi.getName(), fi.getJsonOrigin().get(FIELDS.DEFAULT_VALUE));
+ objectModel.setDirty();
+ result = true;
+ } else { */
+ // we just create a ref to nothing
+ // hoping it will be enriched next time
+ JsonObject refCopy = fi.getJsonOrigin().deepCopy();
+ if (isLookup(fi)) {
+ // remove default targetId, 'cause it will be resolved on next enrich
+ refCopy.remove(FactoredObjectRef.TARGET_ID_FIELD);
+ }
+ printOutput("[DIRTY] CREATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ printOutput("\t" + refCopy.toString());
+ objectProperties.add(fi.getName(), refCopy);
+ objectModel.setDirty();
+ result = true;
+ //}
+ }
+
+ }
+
+
+ }
+ } else {
+ // we found something where must be ref
+ JsonElement currentValue = objectProperties.get(fi.getName());
+ JsonObject refCopy = fi.getJsonOrigin().deepCopy();
+
+ if (currentValue.isJsonObject()) {
+ // this is some object
+ printOutput("CURRENT VALUE [" + currentValue.toString() + "] IS OBJECT IN " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ JsonObject currentObject = currentValue.getAsJsonObject();
+ if (currentObject.has(FIELDS.IS_REF)) {
+ String targetType = currentObject.has(FactoredObjectRef.TARGET_TYPE_FIELD)
+ ?currentObject.get(FactoredObjectRef.TARGET_TYPE_FIELD).getAsString()
+ :null;
+ if (!CommonUtils.isValid(targetType)){
+ String refType = fi.getType();
+ targetType = CommonUtils.isValid(refType)?refType:"*";
+ currentObject.remove(FactoredObjectRef.TARGET_TYPE_FIELD);
+ currentObject.addProperty(FactoredObjectRef.TARGET_TYPE_FIELD, targetType);
+ objectModel.setDirty();
+ }
+ if (!currentObject.has(FIELDS.IS_REF_BY_VALUE_ONLY)
+ || !currentObject.has(FIELDS.REF_FIELD)
+ || !currentObject.has(FIELDS.IS_BACK_REF))
+ {
+ currentObject.addProperty(FIELDS.IS_REF_BY_VALUE_ONLY, fi.isRefByValueOnly());
+ currentObject.addProperty(FIELDS.REF_FIELD, fi.getRefField());
+ currentObject.addProperty(FIELDS.IS_BACK_REF, fi.isBackRef());
+ printOutput("[DIRTY] UPDATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectModel.setDirty();
+ }
+ if (isLookup(fi)) {
+ String lookup = getLookup(fi);
+ JsonElement lookupValue = objectProperties.get(lookup);
+ if (lookupValue.isJsonObject()) {
+ JsonObject lookupObject = lookupValue.getAsJsonObject();
+ if (lookupObject.has(FactoredObjectRef.TARGET_ID_FIELD)) {
+ String lookupTargetId = lookupObject.get(FactoredObjectRef.TARGET_ID_FIELD).getAsString();
+ String lookupTargetType = lookupObject.get(FactoredObjectRef.TARGET_TYPE_FIELD).getAsString();
+ String currentTargetId = currentObject.has(FactoredObjectRef.TARGET_ID_FIELD)
+ ?currentObject.get(FactoredObjectRef.TARGET_ID_FIELD).getAsString()
+ :"";
+ String currentTargetType = currentObject.has(FactoredObjectRef.TARGET_TYPE_FIELD)
+ ?currentObject.get(FactoredObjectRef.TARGET_TYPE_FIELD).getAsString()
+ :"";
+ if (
+ (!lookupTargetId.equals(currentTargetId) && currentTargetType.equals(lookupTargetType))
+ || !CommonUtils.isValid(currentTargetId)
+ ) {
+ currentObject.remove(FactoredObjectRef.TARGET_ID_FIELD);
+ currentObject.add(FactoredObjectRef.TARGET_ID_FIELD, lookupObject.get(FactoredObjectRef.TARGET_ID_FIELD));
+ printOutput("[DIRTY] UPDATED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]"
+ + "\n\tSET LOOKUP TARGET ID TO ["
+ + lookupObject.get(FactoredObjectRef.TARGET_ID_FIELD).toString()
+ + "]");
+ objectModel.setDirty();
+ }
+ }
+ }
+ }
+ result = true;
+ } else if (currentObject.has(FIELDS.FACTORY_ID)) {
+ // it will be replaced with reference on next layout
+ printOutput("[DIRTY] FOUND OBJECT " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectModel.setDirty();
+ result = true;
+ }
+ } else {
+ printOutput("CURRENT VALIE [" + currentValue.toString() + "] IS NOT OBJECT IN " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+
+ }
+
+ if (!result) {
+ // we have something which is not a ref and not a object to produce
+ // we'll treat it as resolved ref value
+ refCopy.remove(FIELDS.DEFAULT_VALUE);
+ refCopy.add(FactoredObjectRef.TARGET_VALUE_FIELD, currentValue);
+ refCopy.addProperty(FactoredObjectRef.IS_RESOLVED_FIELD, true);
+ printOutput("[DIRTY] CONSIDER VALUE [" + currentValue.toString() + "] AS RESOLVED " + fi.getName() + " for [" + fo.getObjectId() + "/" + fo.getObjectType() + "]");
+ objectModel.setDirty();
+ result = true;
+ }
+ }
+ return result;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Generate.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Generate.java
new file mode 100644
index 00000000..46018380
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Generate.java
@@ -0,0 +1,78 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.generationmodel.AbstractTask;
+import ru.entaxy.platform.core.producer.executor.generationmodel.GeneratedList;
+import ru.entaxy.platform.core.producer.executor.generationmodel.GenerationModel;
+
+@CommandExecutor(id = "generate", predecessors = {"validate", "pre-generate"})
+public class Generate extends AbstractCommandExecutor {
+
+ public Generate(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+
+ GenerationModel generationModel = currentResult.findResultObject(GenerationModel.class);
+
+ // generate
+ this.printOutput("\n\t == Execution ==\n");
+ for (AbstractTask at: generationModel.getTasks()) {
+ at.setPrintOutput(isPrintOutput);
+ at.execute(currentResult, commandResult, entaxyProducerService, instructions);
+ this.printOutput("\n :: Result ::\n");
+ if (at.getGeneratedResult()==null)
+ this.printOutput("-> NOTHING");
+ else {
+ Generated g = at.getGeneratedResult();
+ this.printOutput("\tTYPE :: [" + g.getType() + "]");
+ this.printOutput("\tCONTENT :: \n\n");
+ if (g.getObject() == null)
+ this.printOutput("-> EMPTY\n\n");
+ else
+ this.printOutput(g.getObject().toString());
+ }
+ this.printOutput("\n ::\n");
+ }
+ this.printOutput("\n\t ==\n");
+
+ // collect result
+ GeneratedList resultObject = new GeneratedList();
+ for (AbstractTask at: generationModel.getTasks())
+ resultObject.add(at.getGeneratedResult());
+ commandResult.resultObject(resultObject);
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Install.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Install.java
new file mode 100644
index 00000000..edfd514e
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Install.java
@@ -0,0 +1,145 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import org.osgi.framework.Constants;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.core.artifact.Blueprint;
+import ru.entaxy.platform.core.artifact.DeployedArtifact;
+import ru.entaxy.platform.core.artifact.installer.builder.ClusterInstaller;
+import ru.entaxy.platform.core.artifact.installer.builder.InstallationResult;
+import ru.entaxy.platform.core.artifact.installer.builder.Installer;
+import ru.entaxy.platform.core.artifact.installer.builder.LocalInstaller;
+import ru.entaxy.platform.core.artifact.installer.builder.typed.BlueprintInstaller;
+import ru.entaxy.platform.core.artifact.service.ArtifactService;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandInstructions;
+import ru.entaxy.platform.core.producer.executor.support.ArtifactsHelper;
+import ru.entaxy.platform.core.producer.executor.support.DeployedArtifactList;
+import ru.entaxy.platform.core.producer.executor.support.InstallationResultList;
+
+@CommandExecutor(id = "install", predecessors = "deploy")
+public class Install extends AbstractCommandExecutor {
+
+ public static final String INSTALL_LOCAL_INSTRUCTION = "installLocal";
+ public static final String UPDATE_INSTRUCTION = "update";
+ public static final String INSTALL_ONLY_IF_MISSING_INSTRUCTION = "installOnlyIfMissing";
+
+ public Install(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+
+ CommandInstructions commandInstructions = new CommandInstructions(instructions);
+
+ boolean installLocal =
+ commandInstructions.has(INSTALL_LOCAL_INSTRUCTION)
+ ?commandInstructions.getBoolean(INSTALL_LOCAL_INSTRUCTION)
+ :false;
+
+ boolean installOnlyIfMissing =
+ commandInstructions.has(INSTALL_ONLY_IF_MISSING_INSTRUCTION)
+ ?commandInstructions.getBoolean(INSTALL_ONLY_IF_MISSING_INSTRUCTION)
+ :false;
+
+ String update =
+ commandInstructions.has(UPDATE_INSTRUCTION)
+ ?commandInstructions.getString(UPDATE_INSTRUCTION)
+ :null;
+
+ Object installLocalValue = instructions.get(INSTALL_LOCAL_INSTRUCTION);
+ if (installLocalValue != null)
+ if (installLocalValue instanceof Boolean)
+ installLocal = (Boolean)installLocalValue;
+
+ DeployedArtifactList deployedArtifactList = currentResult.findResultObject(DeployedArtifactList.class);
+ InstallationResultList installationResultList = new InstallationResultList();
+
+ ArtifactService artifactService = ArtifactsHelper.getInstance().getArtifactService();
+
+ for (DeployedArtifact da: deployedArtifactList) {
+
+ InstallationResult result = null;
+
+ Installer> installer = null;
+
+ printOutput("-> Installing artifact: [" + da.getArtifact().getCoordinates().toString() + "]");
+ if (installLocal) {
+ LocalInstaller localInstaller = artifactService.installers().local()
+ .artifact(da);
+ installer = localInstaller;
+ printOutput("-> Installing locally");
+ } else {
+ ClusterInstaller clusterInstaller = artifactService.installers().cluster()
+ .artifact(da);
+ installer = clusterInstaller;
+ printOutput("-> Installing clustered");
+ }
+
+ // TODO add support for other types when they appear
+ if (da.getArtifact().getCategory().equals(Blueprint.ARTIFACT_CATEGORY_BLUEPRINT)) {
+ // we're installing blueprint
+ printOutput("-> Installing: " + da.getArtifact().getCategory());
+ BlueprintInstaller blueprintInstaller = installer.typed(BlueprintInstaller.class);
+ if (installOnlyIfMissing)
+ blueprintInstaller.installOnlyIfMissing();
+ if (update != null) {
+ if (!CommonUtils.isValid(update)) {
+ update = da
+ .getArtifact().getProperties()
+ .getOrDefault(Constants.BUNDLE_SYMBOLICNAME, "")
+ .toString();
+ }
+ blueprintInstaller.update(update);
+ }
+ result = blueprintInstaller.start().install();
+ } else {
+ printOutput("-> Unknown category: " + da.getArtifact().getCategory());
+ }
+
+ if (result != null) {
+ for (String key: da.getArtifact().getProperties().keySet())
+ result.getProperties().putIfAbsent(key, da.getArtifact().getProperties().get(key));
+ // TODO imrove Coordinates: add "asMap" method
+ result.getProperties().put("artifact.artifactId", da.getArtifact().getCoordinates().getArtifactId());
+ result.getProperties().put("artifact.groupId", da.getArtifact().getCoordinates().getGroupId());
+ result.getProperties().put("artifact.version", da.getArtifact().getCoordinates().getVersion());
+ result.getProperties().put("artifact.type", da.getArtifact().getCoordinates().getType());
+ result.getProperties().put("artifact.classifier", da.getArtifact().getCoordinates().getClassifier());
+ installationResultList.add(result);
+ }
+ }
+
+ commandResult.resultObject(installationResultList);
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Layout.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Layout.java
new file mode 100644
index 00000000..3b4c8d3a
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Layout.java
@@ -0,0 +1,64 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+
+@CommandExecutor(id = "layout", predecessors = {"analyze"})
+public class Layout extends AbstractCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(Layout.class);
+
+ public Layout(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+ log.debug("Executing command [{}]", getId());
+ ObjectModel objectModel = currentResult.findResultObject(ObjectModel.class);
+
+ printOutput("\n\n\t== LAYOUT == \n\n");
+ printOutput("\n\tIncoming JSON ::\n\n");
+ printOutput(objectModel.getJsonCurrent().toString());
+
+ log.debug(" -- INCOMING JSON --\n" + objectModel.getJsonCurrent().toString());
+ objectModel.layout();
+ log.debug(" -- OUTGOING JSON --\n" + objectModel.getJsonCurrent().toString());
+ commandResult.resultObject(objectModel);
+ printOutput("\n\tOutgoing JSON ::\n\n");
+ printOutput(objectModel.getJsonCurrent().toString());
+ return true;
+ }
+
+
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/PrepareGenerate.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/PrepareGenerate.java
new file mode 100644
index 00000000..4979fad0
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/PrepareGenerate.java
@@ -0,0 +1,58 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.generationmodel.AbstractTask;
+import ru.entaxy.platform.core.producer.executor.generationmodel.GenerationModel;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+
+@CommandExecutor(id = "pre-generate", predecessors = {"validate"})
+public class PrepareGenerate extends AbstractCommandExecutor {
+
+ public PrepareGenerate(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+
+ ObjectModel objectModel = currentResult.findResultObject(ObjectModel.class);
+ GenerationModel generationModel = new GenerationModel(objectModel);
+ generationModel.load();
+
+ // print plan
+ this.printOutput("\n\t == Generation plan ==\n");
+ for (AbstractTask at: generationModel.getTasks())
+ this.printOutput(at.getInfo());
+
+ commandResult.resultObject(generationModel);
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Store.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Store.java
new file mode 100644
index 00000000..79e9d5ec
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Store.java
@@ -0,0 +1,112 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.EntaxyObjectStorage;
+import ru.entaxy.platform.base.objects.EntaxyObjectStorageService;
+import ru.entaxy.platform.base.support.osgi.OSGIUtils;
+import ru.entaxy.platform.core.artifact.DeployedArtifact;
+import ru.entaxy.platform.core.artifact.installer.builder.InstallationResult;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.support.InstallationResultList;
+
+@CommandExecutor(id = "store", predecessors = "install")
+public class Store extends AbstractCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(Store.class);
+
+ protected EntaxyObjectStorageService objectStorageService;
+
+ public Store(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ try {
+ objectStorageService = OSGIUtils.services().ofClass(EntaxyObjectStorageService.class).get();
+ } catch (Exception e) {
+ log.warn("EntaxyObjectStorageService not found yet", e);
+ }
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+
+ InstallationResultList installationResultList = currentResult.findResultObject(InstallationResultList.class);
+
+ if (objectStorageService == null)
+ objectStorageService = OSGIUtils.services().ofClass(EntaxyObjectStorageService.class).get();
+
+ for (InstallationResult installationResult: installationResultList) {
+ printOutput("\n -- INSTALLATION RESULT ::"
+ + "\n\t" + installationResult.getResult().toString()
+ + "\n\tproperties:"
+ + (installationResult.getProperties()==null
+ ?"\n\t\t"
+ :installationResult.getProperties().entrySet().stream()
+ .map(entry->
+ "\n\t\t[" + entry.getKey() + "] = ["
+ + (entry.getValue()==null
+ ?""
+ :(entry.getValue() instanceof DeployedArtifact
+ ?"DeployedArtifact :: " + (
+ ((DeployedArtifact)entry.getValue()).getArtifact()
+ .getProperties().entrySet().stream()
+ .map(e->
+ "\n\t\t\t[" + e.getKey() + "] = ["
+ + (e.getValue()==null
+ ?""
+ :e.getValue().toString()) + "]"
+ ).collect(Collectors.joining())
+ )
+ :entry.getValue().toString()) + "]"
+ )
+ ).collect(Collectors.joining())
+ )
+ );
+
+ EntaxyObjectStorage objectStorage = objectStorageService.getObjectStorage(
+ installationResult.getProperties()
+ .getOrDefault(EntaxyObject.FIELDS.OBJECT_TYPE, "").toString()
+ );
+
+ if (objectStorage == null) {
+ log.warn("Storage not found for type: [" + installationResult.getProperties()
+ .getOrDefault(EntaxyObject.FIELDS.OBJECT_TYPE, "").toString() + "]");
+ continue;
+ }
+
+ objectStorage.store(installationResult.getProperties());
+
+ }
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Validate.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Validate.java
new file mode 100644
index 00000000..3b44f291
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/commands/Validate.java
@@ -0,0 +1,53 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.commands;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
+import ru.entaxy.platform.core.producer.executor.CommandExecutor;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+
+@CommandExecutor(id = "validate", predecessors = {"enrich", "layout"})
+public class Validate extends AbstractCommandExecutor {
+
+ private static final Logger log = LoggerFactory.getLogger(Validate.class);
+
+ public Validate(EntaxyProducerService entaxyProducerService) {
+ super(entaxyProducerService);
+ }
+
+ @Override
+ protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
+ Map instructions) throws Exception {
+ log.info("Executing command [{}]", getId());
+ ObjectModel objectModel = currentResult.findResultObject(ObjectModel.class);
+ // TODO check ObjectModel.objects & .refs for
+ // - factory exists
+ // - output supported
+ return true;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractObjectTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractObjectTask.java
new file mode 100644
index 00000000..d57541f6
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractObjectTask.java
@@ -0,0 +1,33 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+
+public abstract class AbstractObjectTask extends AbstractTask {
+
+ public FactoredObject origin;
+
+ public AbstractObjectTask(FactoredObject factoredObject) {
+ this.origin = factoredObject;
+ }
+
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractRefTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractRefTask.java
new file mode 100644
index 00000000..7543688d
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractRefTask.java
@@ -0,0 +1,32 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectRef;
+
+public abstract class AbstractRefTask extends AbstractTask {
+
+ protected FactoredObjectRef objectRef;
+
+ protected AbstractRefTask(FactoredObjectRef objectRef) {
+ this.objectRef = objectRef;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractTask.java
new file mode 100644
index 00000000..cd97585f
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/AbstractTask.java
@@ -0,0 +1,89 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+
+public abstract class AbstractTask {
+
+ protected boolean isPrintOutput = false;
+
+ protected List oldResults = new LinkedList<>();
+
+ protected Generated generatedResult = null;
+
+ protected AbstractTask mergeTo = null;
+
+ protected boolean isFinal = true;
+
+ public abstract String getInfo();
+
+ public abstract boolean execute(
+ ProducerResult currentResult
+ , CommandResult currentCommand
+ , EntaxyProducerService producerService
+ , Map instructions) throws Exception;
+
+ protected void printOutput(String message) {
+ if (this.isPrintOutput)
+ // OUTPUT TO CONSOLE
+ System.out.println(message);
+ }
+
+ public boolean isPrintOutput() {
+ return isPrintOutput;
+ }
+
+ public void setPrintOutput(boolean isPrintOutput) {
+ this.isPrintOutput = isPrintOutput;
+ }
+
+ public Generated getGeneratedResult() {
+ return generatedResult;
+ }
+
+ public void mergeTo(AbstractTask abstractTask) {
+ this.mergeTo = abstractTask;
+ }
+
+ public boolean isToMerge() {
+ return this.mergeTo != null;
+ }
+
+ public boolean isFinal() {
+ return isFinal;
+ }
+
+ public void setFinal(boolean isFinal) {
+ this.isFinal = isFinal;
+ }
+
+ public void updateGenerated(Generated generated) {
+ oldResults.add(generatedResult);
+ this.generatedResult = generated;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/CalculateTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/CalculateTask.java
new file mode 100644
index 00000000..4591b652
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/CalculateTask.java
@@ -0,0 +1,82 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.objectmodel.Calculation;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+
+public class CalculateTask extends AbstractObjectTask {
+
+ private static final Logger log = LoggerFactory.getLogger(CalculateTask.class);
+
+ public static boolean hasCalculations(FactoredObject factoredObject) {
+ return factoredObject.getInternals().stream().filter(obj -> (obj instanceof Calculation))
+ .count() > 0;
+ }
+
+ public CalculateTask(FactoredObject factoredObject) {
+ super(factoredObject);
+ }
+
+ @Override
+ public String getInfo() {
+ return "CALCULATE FOR " + "[" + origin.getObjectId() + "]";
+ }
+
+ @Override
+ public boolean execute(ProducerResult currentResult, CommandResult currentCommand,
+ EntaxyProducerService producerService, Map instructions) throws Exception {
+
+ ObjectModel objectModel = currentResult.findResultObject(ObjectModel.class);
+
+ List calculations = this.origin.getInternals().stream()
+ .filter(obj -> (obj instanceof Calculation))
+ .map(obj -> (Calculation)obj)
+ .collect(Collectors.toList());
+
+ for (Calculation calculation: calculations) {
+ Object result = calculation.calculate(objectModel, origin);
+ System.out.println("CALCULATION RESOLVED TO :: " + result);
+ System.out.println("\n REPLACE"
+ + "\n\t" + calculation.origin
+ + "\n\tWITH :: " + (new Gson()).toJsonTree(result)
+ + "\n\tAT :: " + calculation.relativePath);
+ JSONUtils.replaceValue(origin.origin, calculation.relativePath, (new Gson()).toJsonTree(result));
+
+ }
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/DefaultObjectDataResolver.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/DefaultObjectDataResolver.java
new file mode 100644
index 00000000..22654e63
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/DefaultObjectDataResolver.java
@@ -0,0 +1,56 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+import ru.entaxy.platform.base.support.JSONUtils;
+
+public class DefaultObjectDataResolver implements ObjectDataResolver {
+
+ @Override
+ public String getSupportedObjectType() {
+ return "*";
+ }
+
+ @Override
+ public Object resolve(EntaxyObject sourceObject, String propertyName) {
+ JsonObject jsonObject = JSONUtils.getJsonRootObject(sourceObject.getConfiguration());
+ if (jsonObject.has(propertyName))
+ return JSONUtils.element2object(jsonObject.get(propertyName));
+ return resolveNotRoot(sourceObject, propertyName, jsonObject);
+ }
+
+ protected Object resolveNotRoot(EntaxyObject sourceObject, String propertyName, JsonObject jsonRoot) {
+ if (!jsonRoot.has(FIELDS.PROPERTIES))
+ return null;
+ JsonElement propertiesElement = jsonRoot.get(FIELDS.PROPERTIES);
+ if (!propertiesElement.isJsonObject())
+ return null;
+ JsonObject properties = propertiesElement.getAsJsonObject();
+ if (!properties.has(propertyName))
+ return null;
+ return JSONUtils.element2object(properties.get(propertyName));
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerateRefTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerateRefTask.java
new file mode 100644
index 00000000..773c0bcd
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerateRefTask.java
@@ -0,0 +1,122 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectProxy;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectRef;
+
+public class GenerateRefTask extends AbstractRefTask {
+
+ protected GenerateRefTask(FactoredObjectRef objectRef) {
+ super(objectRef);
+ }
+
+ @Override
+ public String getInfo() {
+ return "GENERATE-REF " + "[" + objectRef.getTargetId() + "] :: " + objectRef.factoryId;
+ }
+
+ @Override
+ public boolean execute(ProducerResult currentResult, CommandResult currentCommand,
+ EntaxyProducerService producerService, Map instructions) throws Exception {
+ FactoredObject targetObject = this.objectRef.getTargetObject();
+ if (targetObject != null) {
+ if (targetObject instanceof FactoredObjectProxy) {
+ EntaxyObject target = ObjectResolveHelper.getInstance().findObject(
+ this.objectRef.getTargetId(),
+ this.objectRef.getTargetType());
+ if (target == null)
+ throw new IllegalArgumentException("Object not found: ["
+ + this.objectRef.getTargetId()
+ + ":"
+ + this.objectRef.getTargetType()
+ + "]");
+ JsonObject targetConfig = JSONUtils.getJsonRootObject(target.getConfiguration()).deepCopy();
+ JsonObject currentConfig = this.objectRef.origin;
+ JSONUtils.mergeObjects(currentConfig, targetConfig);
+
+ // System.out.println("\n\n\tGENERATING REF WITH CONFIG: \n\t" + targetConfig);
+
+ String factoryId = targetConfig.has(FIELDS.FACTORY_ID)
+ ?targetConfig.get(FIELDS.FACTORY_ID).getAsString()
+ :"";
+
+ String factoryType = targetConfig.has(FIELDS.OBJECT_TYPE)
+ ?targetConfig.get(FIELDS.OBJECT_TYPE).getAsString()
+ :"";
+
+ if (!CommonUtils.isValid(factoryId) || !CommonUtils.isValid(factoryType))
+ throw new IllegalArgumentException("Factory not defined for object: ["
+ + this.objectRef.getTargetId()
+ + ":"
+ + this.objectRef.getTargetType()
+ + "]");
+
+ Map effectiveProperties = createEffectiveProperties(targetConfig, instructions);
+ this.generatedResult = producerService.getProducerForType(factoryType).getFactoryById(factoryId)
+ .generate(EntaxyFactory.CONFIGURATION.OUTPUTS.OUTPUT_TYPE_REF
+ , EntaxyFactory.SCOPE.PRIVATE.label
+ , effectiveProperties);
+
+ }
+ }
+ return true;
+ }
+ protected Map createEffectiveProperties(JsonObject config, Map instructions){
+ Map result = new HashMap<>();
+ result.put(GenerateTask.INSTRUCTIONS_FIELD, instructions);
+ JsonElement effectiveProperties = config.has(FIELDS.PROPERTIES)
+ ?config.get(FIELDS.PROPERTIES)
+ :new JsonObject();
+ if (effectiveProperties.isJsonObject()) {
+ JsonObject jobj = effectiveProperties.getAsJsonObject();
+ for (Entry entry: config.deepCopy().entrySet()) {
+ /*if (entry.getKey().equals(FIELDS.PROPERTIES))
+ continue;*/
+ if (jobj.has(entry.getKey()))
+ continue;
+ jobj.add(entry.getKey(), entry.getValue());
+ }
+ result.putAll(JSONUtils.element2map(effectiveProperties));
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isFinal() {
+ return false;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerateTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerateTask.java
new file mode 100644
index 00000000..dcda3745
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerateTask.java
@@ -0,0 +1,146 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.support.CommonUtils;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+import ru.entaxy.platform.base.objects.EntaxyObject.HEADERS;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+
+public class GenerateTask extends AbstractObjectTask {
+
+ private static final Logger log = LoggerFactory.getLogger(GenerateTask.class);
+
+ public static final String INSTRUCTIONS_FIELD = "##instructions";
+ public static final String GENERATION_PROPERTIES_FIELD = "##generation";
+
+ public String factoryId;
+ public String factoryType;
+ //public String objectId;
+ public JsonElement properties;
+
+ public String outputType = "init";
+ public String scope = "public";
+
+ public Map generationProperties = new HashMap<>();
+
+ public GenerateTask(FactoredObject factoredObject) {
+ super(factoredObject);
+ fillFromOrigin();
+ }
+
+ @Override
+ public boolean execute(ProducerResult currentResult, CommandResult currentCommand,
+ EntaxyProducerService producerService, Map instructions) throws Exception {
+ if (!CommonUtils.isValid(factoryId))
+ throw new IllegalArgumentException("Factory ID is null");
+ if (!CommonUtils.isValid(factoryType))
+ try {
+ EntaxyFactory f = producerService.findFactoryById(factoryId);
+ if (f != null) {
+ log.debug("Factory found by id [{}] with type [{}]", f.getFactoryId(), f.getFactoryType());
+ factoryType = f.getFactoryType();
+ } else
+ throw new IllegalArgumentException("Factory not found: " + factoryId);
+ } catch (Exception e) {
+ throw e;
+ }
+ log.debug("Execute for type [{}] with factoryId [{}]", factoryType, factoryId);
+ Map effectiveProperties = createEffectiveProperties(instructions);
+ this.generatedResult = producerService.getProducerForType(factoryType).getFactoryById(factoryId).generate(outputType, scope, effectiveProperties);
+ // objectId could be changed by pre/post processor, so we update it
+ // TODO move string to const
+ String objectId = this.generatedResult.getProperties()
+ .getOrDefault(FIELDS.OBJECT_ID, origin.getObjectId()).toString();
+ if (!origin.getObjectId().equals(objectId)) {
+ log.debug("Changing objectId from [{}] to [{}]", origin.getObjectId(), objectId);
+ origin.setObjectId(objectId);
+ }
+ GeneratedHeaders headers = GeneratedHeaders.getHeaders(this.generatedResult.getProperties());
+ headers.set(HEADERS.MAIN_OBJECT, origin.getObjectId() + ":" + factoryType);
+ headers.append(HEADERS.GENERATED_OBJECTS, origin.getObjectId() + ":" + factoryType);
+ // headers.set(GeneratedHeaders.HEADER_MAIN_OBJECT_TYPE, factoryType);
+ // headers.set(GeneratedHeaders.HEADER_MAIN_OBJECT_FACTORY_ID, factoryId);
+ // headers.append(GeneratedHeaders.HEADER_OBJECT_ID, origin.getObjectId());
+ // headers.append(GeneratedHeaders.HEADER_OBJECT_TYPE, factoryType);
+ headers.append(HEADERS.GENERATED_OBJECTS_CONFIG
+ , Base64.getEncoder().encodeToString(origin.origin.toString().getBytes()));
+ this.generationProperties.clear();
+ this.generationProperties.putAll(effectiveProperties);
+ this.generatedResult.getProperties().put(GENERATION_PROPERTIES_FIELD, new HashMap(this.generationProperties));
+ return true;
+ }
+
+ protected Map createEffectiveProperties(Map instructions){
+ Map result = new HashMap<>();
+ result.put(INSTRUCTIONS_FIELD, instructions);
+ JsonElement effectiveProperties = this.properties.deepCopy();
+ if (effectiveProperties.isJsonObject()) {
+ JsonObject jobj = effectiveProperties.getAsJsonObject();
+ for (Entry entry: origin.origin.entrySet()) {
+ /*if (entry.getKey().equals(FIELDS.PROPERTIES))
+ continue;*/
+ if (jobj.has(entry.getKey()))
+ continue;
+ jobj.add(entry.getKey(), entry.getValue());
+ }
+ result.putAll(JSONUtils.element2map(effectiveProperties));
+ }
+ return result;
+ }
+
+ public void fillFromOrigin() {
+ this.factoryId = origin.factoryId;
+ // this.objectId = origin.getObjectId();
+ this.factoryType = origin.getObjectType();
+ this.scope = origin.scope;
+ this.properties = origin.origin.get(FIELDS.PROPERTIES);
+
+ if (CommonUtils.isValid(origin.getOutputType()))
+ this.outputType = origin.getOutputType();
+
+ }
+
+ public void updateObjectId(String objectId) {
+ // this.objectId = objectId;
+ this.origin.setObjectId(objectId);
+ }
+
+ @Override
+ public String getInfo() {
+ return "GENERATE " + "[" + origin.getObjectId() + "] :: " + factoryId + "/" + outputType;
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GeneratedHeaders.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GeneratedHeaders.java
new file mode 100644
index 00000000..4dc60c4d
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GeneratedHeaders.java
@@ -0,0 +1,85 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+public class GeneratedHeaders {
+
+ public static final String HEADERS_PROPERTY = "##headers";
+
+ public static GeneratedHeaders getHeaders(Map properties) {
+ if (!properties.containsKey(HEADERS_PROPERTY))
+ properties.put(HEADERS_PROPERTY, new GeneratedHeaders());
+ return (GeneratedHeaders)properties.get(HEADERS_PROPERTY);
+ }
+
+ Map headers = new HashMap<>();
+
+ public void set(String name, Object value) {
+ this.headers.put(name, value);
+ }
+
+ public void append(String name, Object value) {
+ if (!headers.containsKey(name))
+ headers.put(name, new LinkedList());
+ else {
+ Object obj = headers.get(name);
+ if (!(obj instanceof List>)) {
+ List list = new LinkedList();
+ list.add(obj);
+ }
+ }
+ List list = (List)headers.get(name);
+ list.add(value);
+ }
+
+ public Map getAsStringMap(){
+ Map result = new HashMap<>();
+ for (Entry entry: headers.entrySet())
+ result.put(entry.getKey(), getValueAsString(entry.getValue()));
+ return result;
+ }
+
+ protected String getValueAsString(Object value) {
+ if (value == null)
+ return "";
+ if (value instanceof Map,?>)
+ return getMapValueAsString((Map,?>)value);
+ if (value instanceof List>)
+ return getListValueAsString((List)value);
+ return value.toString();
+ }
+
+ protected String getMapValueAsString(Map,?> value) {
+ return "[" + value.entrySet().stream().filter(e -> e.getKey()!=null)
+ .map(e -> e.getKey().toString()+"="+getValueAsString(e.getValue()))
+ .collect(Collectors.joining(",")) + "]";
+ }
+
+ protected String getListValueAsString(List> value) {
+ return value.stream().map(obj->getValueAsString(obj)).collect(Collectors.joining(","));
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GeneratedList.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GeneratedList.java
new file mode 100644
index 00000000..882fe900
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GeneratedList.java
@@ -0,0 +1,36 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.Collections;
+
+import org.apache.commons.collections4.list.AbstractLinkedList;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+
+public class GeneratedList extends AbstractLinkedList {
+
+ public GeneratedList() {
+ // to avoid NPE we must either call constructor with parameters
+ // or call init() in constructor
+ super(Collections.emptyList());
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerationModel.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerationModel.java
new file mode 100644
index 00000000..5beb4b8a
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/GenerationModel.java
@@ -0,0 +1,138 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObject;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectProxy;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectRef;
+import ru.entaxy.platform.core.producer.executor.objectmodel.ObjectModel;
+
+public class GenerationModel {
+
+ protected ObjectModel objectModel;
+
+ protected List tasks = new LinkedList<>();
+
+ public Map> objectToTasksMap = new HashMap<>();
+
+ public GenerationModel(ObjectModel objectModel) {
+ this.objectModel = objectModel;
+ }
+
+ public void load() {
+ for (FactoredObject fo: objectModel.objects)
+ if (!fo.isEmbedded())
+ tasks.addAll(generateTasksForObject(fo));
+ }
+
+ protected List generateTasksForObject(FactoredObject fo) {
+
+ if (fo instanceof FactoredObjectProxy)
+ return Collections.singletonList(new ResolveObjectTask((FactoredObjectProxy)fo));
+
+ List localPreTasks = new LinkedList<>();
+ List localPostTasks = new LinkedList<>();
+
+ // first process embedded objects
+
+ List embedded = fo.embedded.stream().filter(f->(f instanceof FactoredObject))
+ .map(f -> (FactoredObject)f)
+ .collect(Collectors.toList());
+ for (FactoredObject embeddedObject: embedded) {
+ List tasksForEmbedded = generateTasksForObject(embeddedObject);
+ localPreTasks.addAll(tasksForEmbedded);
+ }
+
+ // process links to externalized embedded objects
+
+ List embeddedLinks = fo.embedded.stream().filter(f->(f instanceof FactoredObjectRef))
+ .map(f -> (FactoredObjectRef)f)
+ .filter(f -> !f.isBackRef())
+ .filter(f -> f.isLink())
+ .collect(Collectors.toList());
+ for (FactoredObjectRef embeddedRef: embeddedLinks) {
+ FactoredObject embeddedObject = embeddedRef.getTargetObject();
+ List tasksForEmbedded = generateTasksForObject(embeddedObject);
+
+ // check the dependencies:
+ // if embedded depends on main
+ // then it must be generates after the main
+
+ List refs = objectModel.refs.stream()
+ .filter(r -> r.isDefinedIn(embeddedObject))
+ .filter(r -> fo.equals(r.getTargetObject()))
+ .collect(Collectors.toList());
+ if (refs.isEmpty())
+ localPreTasks.addAll(tasksForEmbedded);
+ else
+ localPostTasks.addAll(tasksForEmbedded);
+ }
+
+ // process embedded refs
+
+ List embeddedRefs = fo.embedded.stream().filter(f->(f instanceof FactoredObjectRef))
+ .map(f -> (FactoredObjectRef)f)
+ .filter(f -> !f.isBackRef())
+ .filter(f -> !f.isLink())
+ .collect(Collectors.toList());
+ for (FactoredObjectRef embeddedRef: embeddedRefs) {
+
+ if (!embeddedRef.isLink()) {
+ localPreTasks.add(new ResolveRefTask(embeddedRef));
+ if (!embeddedRef.isRefByValueOnly())
+ localPreTasks.add(new GenerateRefTask(embeddedRef));
+ }
+ }
+
+ List currentTasks = new ArrayList<>(localPreTasks);
+
+ if (CalculateTask.hasCalculations(fo))
+ currentTasks.add(new CalculateTask(fo));
+
+ GenerateTask generateTask = new GenerateTask(fo);
+
+ currentTasks.add(generateTask);
+
+ for (AbstractTask at: localPreTasks)
+ if (((at instanceof GenerateTask) || (at instanceof GenerateRefTask)) && !at.isToMerge() )
+ currentTasks.add(new MergeTask(at, generateTask));
+
+ currentTasks.addAll(localPostTasks);
+
+ for (AbstractTask at: localPostTasks)
+ if (((at instanceof GenerateTask) || (at instanceof GenerateRefTask)) && !at.isToMerge())
+ currentTasks.add(new MergeTask(at, generateTask));
+
+ return currentTasks;
+ }
+
+ public List getTasks() {
+ return tasks;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/MergeTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/MergeTask.java
new file mode 100644
index 00000000..4e9b3dbc
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/MergeTask.java
@@ -0,0 +1,106 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.factory.EntaxyFactoryException;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.generationmodel.merge.MergeHelper;
+
+public class MergeTask extends AbstractTask {
+
+ private static final Logger log = LoggerFactory.getLogger(MergeTask.class);
+
+ protected AbstractTask fromTask;
+ protected AbstractTask toTask;
+
+ public MergeTask(AbstractTask fromTask, AbstractTask toTask) {
+ this.fromTask = fromTask;
+ this.toTask = toTask;
+ this.fromTask.mergeTo(this.toTask);
+ }
+
+ @Override
+ public String getInfo() {
+ return "MERGE: " + "\n\t FROM: " + fromTask.getInfo() + "\n\t TO: " + toTask.getInfo();
+ }
+
+ @Override
+ public boolean execute(ProducerResult currentResult, CommandResult currentCommand,
+ EntaxyProducerService producerService, Map instructions) throws Exception {
+
+ Generated source = this.fromTask.getGeneratedResult();
+ Generated target = this.toTask.getGeneratedResult();
+
+ if ( (source!=null) && (target != null)) {
+
+ if (!MergeHelper.getInstance().canMerge(source.getType(), target.getType())) {
+ printOutput("CAN'T MERGE " + source.getType() + " TO " + target.getType());
+ log.error("CAN'T MERGE " + source.getType() + " TO " + target.getType());
+ throw new EntaxyFactoryException();
+ }
+
+ this.generatedResult = MergeHelper.getInstance().merge(source, target);
+
+ // merge headers
+
+ GeneratedHeaders sourceGeneratedHeaders = GeneratedHeaders.getHeaders(source.getProperties());
+ GeneratedHeaders targetGeneratedHeaders = GeneratedHeaders.getHeaders(target.getProperties());
+
+ GeneratedHeaders resultGeneratedHeaders = GeneratedHeaders.getHeaders(this.generatedResult.getProperties());
+
+ for (String header: targetGeneratedHeaders.headers.keySet())
+ resultGeneratedHeaders.set(header, targetGeneratedHeaders.headers.get(header));
+
+ for (String header: sourceGeneratedHeaders.headers.keySet())
+ if (EntaxyObject.HEADERS.MAIN_OBJECT.equals(header))
+ continue;
+ else
+ resultGeneratedHeaders.append(header, sourceGeneratedHeaders.headers.get(header));
+ } else {
+ if (source != null)
+ this.generatedResult = source;
+ else if (target != null)
+ this.generatedResult = target;
+ else
+ // nothing to do
+ return true;
+ }
+
+ this.fromTask.setFinal(false);
+ this.toTask.updateGenerated(generatedResult);
+
+ // prevent building result of this task
+ this.generatedResult = null;
+
+ return true;
+ }
+
+
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ObjectDataResolver.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ObjectDataResolver.java
new file mode 100644
index 00000000..519659e5
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ObjectDataResolver.java
@@ -0,0 +1,29 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+
+public interface ObjectDataResolver {
+
+ public String getSupportedObjectType();
+ public Object resolve(EntaxyObject sourceObject, String propertyName);
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ObjectResolveHelper.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ObjectResolveHelper.java
new file mode 100644
index 00000000..6f8da6de
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ObjectResolveHelper.java
@@ -0,0 +1,84 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.CollectionType;
+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 org.osgi.service.component.annotations.ReferencePolicyOption;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.base.objects.EntaxyObjectService;
+
+@Component(service = ObjectResolveHelper.class, immediate = true)
+public class ObjectResolveHelper {
+
+ public static ObjectResolveHelper _INSTANCE;
+
+ public static ObjectResolveHelper getInstance(){
+ return _INSTANCE;
+ }
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ EntaxyObjectService entaxyObjectService;
+
+ protected Map externalResolvers = new HashMap<>();
+
+ DefaultObjectDataResolver defaultObjectDataResolver = new DefaultObjectDataResolver();
+
+ @Activate
+ public void activate() {
+ _INSTANCE = this;
+ }
+
+ @Reference(unbind = "removeResolver", cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC,
+ policyOption = ReferencePolicyOption.GREEDY, collectionType = CollectionType.SERVICEOBJECTS, service = ObjectDataResolver.class)
+ public void addResolver(ObjectDataResolver resolver) {
+ synchronized (externalResolvers) {
+ externalResolvers.put(resolver.getSupportedObjectType(), resolver);
+ }
+ }
+
+ public void removeResolver(ObjectDataResolver resolver) {
+ synchronized (externalResolvers) {
+ externalResolvers.remove(resolver.getSupportedObjectType());
+ }
+ }
+
+ public EntaxyObject findObject(String objectId, String objectType) {
+ return entaxyObjectService.getObjects().stream()
+ .filter(obj -> (obj.getObjectId().equals(objectId) && obj.getObjectType().equals(objectType)))
+ .findFirst().orElse(null);
+ }
+
+ public ObjectDataResolver getResolver(EntaxyObject object) {
+ return externalResolvers.getOrDefault(object.getObjectType(), defaultObjectDataResolver);
+ }
+
+ public Object resolve(EntaxyObject entaxyObject, String propertyName) {
+ return getResolver(entaxyObject).resolve(entaxyObject, propertyName);
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ResolveObjectTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ResolveObjectTask.java
new file mode 100644
index 00000000..a6c442c8
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ResolveObjectTask.java
@@ -0,0 +1,67 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.Map;
+
+import ru.entaxy.platform.base.objects.EntaxyObject;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectProxy;
+
+public class ResolveObjectTask extends AbstractTask {
+
+ public FactoredObjectProxy origin;
+
+ public EntaxyObject targetObject;
+
+ public ResolveObjectTask(FactoredObjectProxy object) {
+ super();
+ this.origin = object;
+ }
+
+ @Override
+ public String getInfo() {
+ return "RESOLVE-OBJECT "
+ + "["
+ + origin.getObjectId()
+ + " : "
+ + origin.getObjectType()
+ + "]";
+ // + objectRef.factoryId;
+ }
+ @Override
+ public boolean execute(ProducerResult currentResult, CommandResult currentCommand,
+ EntaxyProducerService producerService, Map instructions) throws Exception {
+
+ String targetId = origin.getObjectId();
+ String targetType = origin.getObjectType();
+
+ this.targetObject = ObjectResolveHelper.getInstance().findObject(targetId, targetType);
+
+ if (this.targetObject == null) {
+ throw new IllegalArgumentException("Object not found: " + targetId + ":" + targetType);
+ }
+
+ return true;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ResolveRefTask.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ResolveRefTask.java
new file mode 100644
index 00000000..c5f9dfcf
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/ResolveRefTask.java
@@ -0,0 +1,99 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.google.gson.Gson;
+
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+import ru.entaxy.platform.base.support.JSONUtils;
+import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
+import ru.entaxy.platform.core.producer.api.ProducerResult;
+import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
+import ru.entaxy.platform.core.producer.executor.objectmodel.FactoredObjectRef;
+
+public class ResolveRefTask extends AbstractRefTask {
+
+ protected ResolveRefTask(FactoredObjectRef objectRef) {
+ super(objectRef);
+ }
+
+ @Override
+ public String getInfo() {
+ return "RESOLVE-REF "
+ + "["
+ + objectRef.definedIn.getObjectId()
+ + "] -> "
+ + "["
+ + objectRef.getTargetId()
+ + "]";
+ // + objectRef.factoryId;
+ }
+
+ @Override
+ public boolean execute(ProducerResult currentResult, CommandResult currentCommand,
+ EntaxyProducerService producerService, Map instructions) throws Exception {
+ GenerationModel generationModel = currentResult.findResultObject(GenerationModel.class);
+ String fieldName = objectRef.getOrDefault(FIELDS.REF_FIELD, FIELDS.OBJECT_ID).toString();
+ printOutput("RESOLVING REF TO FIELD [" + fieldName + "]");
+ List generateTasks = generationModel.tasks.stream()
+ .filter(t->(t instanceof GenerateTask))
+ .map(t->(GenerateTask)t)
+ .filter(t->t.origin==objectRef.getTargetObject())
+ .collect(Collectors.toList());
+ if (generateTasks.size() == 0)
+ generateTasks = generationModel.tasks.stream()
+ .filter(t->(t instanceof ResolveObjectTask))
+ .map(t->(ResolveObjectTask)t)
+ .filter(t->t.origin==objectRef.getTargetObject())
+ .collect(Collectors.toList());
+ if (generateTasks.size() == 0) {
+ printOutput("None of GenerateTask or ResolveObjectTask found for [" + objectRef.getTargetId() + "/" + objectRef.getTargetObject().getObjectType() + "]");
+ return false;
+ }
+ AbstractTask provider = generateTasks.get(0);
+ Object value = null;
+ if (provider instanceof GenerateTask) {
+ GenerateTask generateTask = (GenerateTask)provider;
+ value = generateTask.generationProperties.getOrDefault(fieldName, "");
+ } else if (provider instanceof ResolveObjectTask) {
+ ResolveObjectTask task = (ResolveObjectTask)provider;
+ value = ObjectResolveHelper.getInstance().resolve(task.targetObject, fieldName);
+ if (value == null)
+ value = "";
+ }
+ printOutput("RESOLVED REF TO FIELD [" + fieldName + "] to VALUE [" + value.toString() + "]");
+ printOutput("REPLACE: [" + objectRef.origin.toString() + "] in PATH ["
+ + objectRef.relativePath + "] in OBJECT "
+ + objectRef.definedIn.origin.toString() );
+ JSONUtils.replaceValue(objectRef.definedIn.origin, objectRef.relativePath, (new Gson()).toJsonTree(value));
+ printOutput("AFTER REPLACEMENT: [" + objectRef.definedIn.origin.toString() + "]");
+ return true;
+ }
+
+ @Override
+ public boolean isFinal() {
+ return false;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/AbstractMergeProcessor.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/AbstractMergeProcessor.java
new file mode 100644
index 00000000..ec947e6a
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/AbstractMergeProcessor.java
@@ -0,0 +1,56 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel.merge;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ru.entaxy.platform.core.producer.executor.generationmodel.merge.MergingMap.Mapping;
+
+public abstract class AbstractMergeProcessor implements MergeProcessor {
+
+ protected Map> mapping;
+
+
+ protected AbstractMergeProcessor() {
+ super();
+ mapping = new HashMap<>();
+ if (this.getClass().isAnnotationPresent(MergingMap.class)) {
+ MergingMap map = this.getClass().getAnnotation(MergingMap.class);
+ Mapping[] mappings = map.mappings();
+ if (mappings != null)
+ for (int i=0; i> getMergingMap() {
+ return mapping;
+ }
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/BlueprintMergeProcessor.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/BlueprintMergeProcessor.java
new file mode 100644
index 00000000..4618cbaa
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/BlueprintMergeProcessor.java
@@ -0,0 +1,111 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel.merge;
+
+import java.util.Map;
+
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+import ru.entaxy.platform.base.support.xml.CommonXMLUtils;
+import ru.entaxy.platform.core.producer.executor.generationmodel.merge.MergingMap.Mapping;
+
+@Component(service = MergeProcessor.class, immediate = true)
+@MergingMap(mappings = {
+ @Mapping(source = Generated.GENERATED_TYPE_BLUEPRINT_FRAGMENT, targets = {Generated.GENERATED_TYPE_BLUEPRINT})
+})
+public class BlueprintMergeProcessor extends AbstractMergeProcessor {
+
+ private static final Logger log = LoggerFactory.getLogger(BlueprintMergeProcessor.class);
+
+ @Override
+ public Generated merge(Generated source, Generated target, Map config) {
+
+ NodeList sourceNodes = null;
+ if (source.getType().equals(Generated.GENERATED_TYPE_BLUEPRINT_FRAGMENT)) {
+ String toParse = "" + source.getObject().toString() + " ";
+ try {
+ Document sourceDoc = CommonXMLUtils.parseString(true, toParse);
+ sourceNodes = sourceDoc.getFirstChild().getChildNodes();
+ for (int i=0; i wrappersMap = new HashMap<>();
+
+ protected Map> processors = new HashMap<>();
+
+ @Activate
+ public void activate(ComponentContext componentContext) {
+ _INSTANCE = this;
+ }
+
+ @Reference(unbind = "removeMergeProcessor", cardinality = ReferenceCardinality.MULTIPLE, collectionType = CollectionType.SERVICE
+ , policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, service = MergeProcessor.class)
+ public void addMergeProcessor(MergeProcessor mergeProcessor) {
+
+ MergeProcessorWrapper wrapper = new MergeProcessorWrapper(mergeProcessor);
+
+ synchronized (this.wrappersMap) {
+ this.wrappersMap.put(mergeProcessor, wrapper);
+ }
+
+ Map> mapping = mergeProcessor.getMergingMap();
+
+ synchronized (this.processors) {
+ for (Map.Entry> entry: mapping.entrySet()) {
+ this.processors.putIfAbsent(entry.getKey(), new HashMap<>());
+ Map map = this.processors.get(entry.getKey());
+ for (String target: entry.getValue())
+ map.put(target, wrapper);
+ }
+ }
+
+ }
+
+ public void removeMergeProcessor(MergeProcessor mergeProcessor) {
+ synchronized (wrappersMap) {
+ if (wrappersMap.containsKey(mergeProcessor)) {
+ wrappersMap.get(mergeProcessor).mergeProcessor = null;
+ wrappersMap.remove(mergeProcessor);
+ }
+ }
+ }
+
+ public boolean canMerge(String source, String target) {
+ return processors.containsKey(source)
+ && processors.get(source).containsKey(target)
+ && processors.get(source).get(target).mergeProcessor != null;
+ }
+
+ public Generated merge(Generated source, Generated target) {
+ if (!canMerge(source.getType(), target.getType()))
+ return null;
+ return processors.get(source.getType()).get(target.getType()).mergeProcessor.merge(source, target);
+ }
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/MergeProcessor.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/MergeProcessor.java
new file mode 100644
index 00000000..5a12f080
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/MergeProcessor.java
@@ -0,0 +1,38 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel.merge;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
+
+public interface MergeProcessor {
+
+ Map> getMergingMap();
+
+ default Generated merge(Generated source, Generated target) {
+ return this.merge(source, target, new HashMap<>());
+ };
+
+ Generated merge(Generated source, Generated target, Map config);
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/MergingMap.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/MergingMap.java
new file mode 100644
index 00000000..a2338a11
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/generationmodel/merge/MergingMap.java
@@ -0,0 +1,39 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * object-producer-core
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.generationmodel.merge;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(RUNTIME)
+@Target(TYPE)
+public @interface MergingMap {
+
+ public @interface Mapping {
+ String source();
+ String[] targets();
+ }
+
+ Mapping[] mappings();
+
+}
diff --git a/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/objectmodel/AbstractFactored.java b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/objectmodel/AbstractFactored.java
new file mode 100644
index 00000000..12415fe6
--- /dev/null
+++ b/platform/runtime/core/object-producing/object-producer-core/src/main/java/ru/entaxy/platform/core/producer/executor/objectmodel/AbstractFactored.java
@@ -0,0 +1,96 @@
+/*-
+ * ~~~~~~licensing~~~~~~
+ * test-producers
+ * ==========
+ * Copyright (C) 2020 - 2022 EmDev LLC
+ * ==========
+ * 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.
+ * ~~~~~~/licensing~~~~~~
+ */
+package ru.entaxy.platform.core.producer.executor.objectmodel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonObject;
+
+import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
+
+
+public abstract class AbstractFactored extends AbstractItem {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractFactored.class);
+
+ public static boolean isFactored(JsonObject jsonObject) {
+ if (jsonObject.has(FIELDS.FACTORY_ID)) {
+ String factoryId = jsonObject.get(FIELDS.FACTORY_ID).getAsString();
+ return (factoryId != null) && !factoryId.isBlank();
+ }
+ return false;
+ }
+
+ public static AbstractFactored getContextOwner(Map context) {
+ initContext(context);
+ @SuppressWarnings("unchecked")
+ List list = (List)context.get(FACTORED_CONTEXT_KEY);
+ if (!list.isEmpty()) {
+ return list.get(list.size()-1);
+ }
+ return null;
+ }
+
+
+ public String factoryId;
+ public String scope = "public";
+ public String ownScope = "";
+
+ public List internalItems = new ArrayList<>();
+
+ protected AbstractFactored(ObjectModel objectModel) {
+ super(objectModel);
+ }
+
+ public void addInternal(AbstractItem item) {
+ if (!this.internalItems.contains(item))
+ this.internalItems.add(item);
+ }
+
+ public List getInternals(){
+ return this.internalItems;
+ }
+
+ protected void joinContext(Map context) {
+ initContext(context);
+ @SuppressWarnings("unchecked")
+ List list = (List)context.get(FACTORED_CONTEXT_KEY);
+ list.add(this);
+ }
+
+ protected void leaveContext(Map context) {
+ initContext(context);
+ @SuppressWarnings("unchecked")
+ List list = (List)context.get(FACTORED_CONTEXT_KEY);
+ list.remove(this);
+ }
+
+ public void wrap(JsonObject object, Map