diff --git a/documentation/Management layer.postman_collection.json b/documentation/Management layer.postman_collection.json index b2669b0..3dafc22 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 8bf7592..33b82fb 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 0000000..2d23c1b --- /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 0000000..bab4d67 Binary files /dev/null and b/documentation/extras/eav_objects.png differ diff --git a/documentation/index.adoc b/documentation/index.adoc index e2ce5ff..ed0cf6d 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 94fda99..496675e 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 3f84068..c15d61a 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 5df74f5..ff2ccea 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 0000000..8b8b773 --- /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 cb83b29..0dddc8a 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 9eb9a67..fceecb9 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 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 3d2fd6e..6c9831a 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 0000000..261eeb9 --- /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 0000000..98a4732 --- /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 0000000..8d8be5c --- /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 0000000..8e0660f --- /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 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 0000000..3248795 --- /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 0000000..9c5b278 --- /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 0000000..d864023 --- /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 0000000..8c2e58f --- /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 0000000..2da78f4 --- /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 e1b980b..0d7cb55 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 81c7598..9830732 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 cd9f7e1..70befc0 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 9781d76..f3ab725 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 048d1d7..f286f69 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 eb36609..3bf77de 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 95aedb5..229cffb 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 54dafac..bed0585 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 c8eb663..b6542fa 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 2a0c189..7f984ee 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 d9966f6..4d6a767 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 0cf8cd7..01c745c 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 0000000..d571e02 --- /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 f145fa4..42a2102 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 0000000..9b65317 --- /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 0000000..df1a1f3 --- /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 aff7c93..5896815 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 8438ad6..e95c404 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 b287e1c..da3898b 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 3c2d802..d3530a6 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 d7a9c40..1116fab 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 c31c77b..2a1986b 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 5e1ce99..ca3be27 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 48a13f3..dfb5f23 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 f7b3d14..c324042 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 379ef8c..9dc4417 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 5f0a8f5..4784f7a 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 fb88e28..b716b3e 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 346a1f2..a64365f 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 cd469a5..de52563 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 ce49e0a..15dcd30 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 ee86d45..e1dd388 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 0396a93..2792e3b 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 80377e4..4c842f7 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 9931036..d7b953d 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 c7eda26..9d435ea 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