Написание адаптеров - rsugio/cpi GitHub Wiki
Руководство по процедурам написания адаптеров для SAP CPI
версия 0.0.2 от 01 июня 2020г Илья Кузнецов [email protected] или [email protected]
Обсуждать можно в https://t.me/sapdevelopment
В этой серии вы увидите:
- символы Ёё«»Ѣѣ
- процедуры -- упор на то, какая последовательность работает, с дословной копипастой
- установка средств разработки
- пример с :camel:
TODO:
- Установка клауд-коннектора
- Ссылка на документ по Operations API
Рабочее место разработчика
Java
Ставим JDK 8 - обязательно 64 бита. Прописываем JAVA_HOME
. На момент статьи это 1.8.0_251.
Восьмёрка -- потому что слоупоки детектед текущий CPI работает на SAP JVM 8, равно как и CloudConnector.
Системы сборки
Maven
https://maven.apache.org/download.html и устанавливаем локальный мавен, он пригодится для генерации проектов и вообще
для многих дел. У меня это C:\int\apache\apache-maven-3.6.2\
,
прописан в путях пользователя как C:\int\apache\apache-maven-3.6.2\bin
. Проверяем запуск:
> mvn -version
Apache Maven 3.6.2 (40f52333136460af0dc0d7232c0dc0bcf0d9e117; 2019-08-27T18:06:16+03:00)
Maven home: C:\int\apache\apache-maven-3.6.2\bin\..
Java version: 1.8.0_251, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk1.8.0_251\jre
Default locale: en_US, platform encoding: Cp1251
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
Gradle
https://gradle.org/install/ и ставим локальный гредл. Это в целом в индустрии разработки необязательно но мне так сильно проще. Прописываем в путях пользователя, проверяем:
> gradle -version
------------------------------------------------------------
Gradle 6.4
------------------------------------------------------------
Build time: 2020-05-05 19:18:55 UTC
Revision: 42f7c3d0c3066b7b38bd0726760d4881e86fd19f
Kotlin: 1.3.71
Groovy: 2.5.10
Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM: 1.8.0_251 (Oracle Corporation 25.251-b08)
OS: Windows 10 10.0 amd64
Затмение курильщика
Заходим на https://tools.hana.ondemand.com/#cloudintegration
и по ссылке https://www.eclipse.org/downloads/packages/release/oxygen/3a/eclipse-jee-oxygen-3a скачиваем именно эту
версию. Распаковываем, прописываем в eclipse.ini
первыми двумя строками:
-vm
C:/Program Files/Java/jdk1.8.0_251/bin
Запускаем, добавляем сайт обновления https://tools.hana.ondemand.com/oxygen и устанавливаем такие штуки:
SAP Cloud Platform Integration Tools
Adapter Development Kit
Operations
Вы можете поставить также SAP Cloud Platform Tools
, здесь это не требуется.
Для проверки открываем перспективу Integration Operations
и в свойствах прописываем Operations Server
:
URL = https://d0451-tmn.hci.eu1.hana.ondemand.com <-- конечно здесь у вас другой будет
Вводим логин/пароль и проверяем соединение. Данный плагин использует Operations API
, исторически первый для HCI и FSM,
и позволяет делать очень много интересных штук -- про это /* TODO */
отдельный документ.
Вторая проверка -- создаём новый проект по Ctrl-N и выбираем SAP Cloud Platform Integration / Adapter Project, смотрим появляется ли этот диалог.
Я также рекомендую отдельно скачать этот плагин для исследований так:
@echo off
set URL=https://tools.hana.ondemand.com/oxygen/
set DST=./cpi-oxygen
rem путь к вашему эклипсу здесь
set ECL=c:\int\Eclipses\eclipse_oxygen\eclipsec.exe
%ECL% -application org.eclipse.equinox.p2.metadata.repository.mirrorApplication -source %URL% -destination %DST%
%ECL% -application org.eclipse.equinox.p2.artifact.repository.mirrorApplication -source %URL% -destination %DST%
Как вы уже знаете по опыту наземного ява-стека, без изучения существующих решений (артефакты и система сборки) рассчитывать на продуктивную работу наивно.
Cloud Connector
Я рекомендую также установить на свой компьютер КК и зарегистрировать его. Это много удобнее и совершенно бесплатно. /* TODO */
Идея здорового человека
Устанавливаем IntelliJ Idea, бесплатный Community Edition вполне достаточен. Все настройки по умолчанию, если вы не знаете что выбрать.
Я даже рекомендую по своему опыту начать установку не с IDE а по шагам:
- Создать сквозной аккаунт на https://jetbrains.com и https://hyperskill.org
- Скачать https://www.jetbrains.com/toolbox-app/, установить тулбокс и в нём залогиниться в аккаунт
- В Тулбоксе сделать настройки, куда ставить продукты JetBrains (я ставлю в
C:\int\jetbrains
) и выбрать Community Edition к установке
В дальнейшем ToolBox вам сильно облегчит жизнь и запуск проектов.
Для IDEA есть отличный Camel-plugin от Клауса Ибсена (автора Camel), я рекомендую поставить его, тогда вы увидите подсказки по параметрам стандартных компонент.
Первый подход к снаряду: создаём Camel-компонент
Это всё очень хорошо изложено в Camel in Action, раздел 8.4 Developing custom components
.
Есть папка C:\webinars\2020-06-02-cpiadapter
в которой батник generate.bat
:
mvn archetype:generate -B ^
-DarchetypeGroupId=org.apache.camel.archetypes -DarchetypeArtifactId=camel-archetype-component -DarchetypeVersion=2.17.4 ^
-DgroupId=demo.cpi -DartifactId=coffee_comp -Dversion=0.0.1 ^
-Dname=CpiCoffee -Dscheme=coffee
cd coffee_comp && mvn install
rem Для господ юниксоидов - заменяйте концевые ^ на \
Это должно у вас работать из командной строки, при первом запуске будет вытягивать много артефактов
и складывать их в %USERPROFILE%/.m2
и куда-то ещё. Если у вас прокси -- пропишите его где-то
в настройках мэвена.
org.apache.camel.archetypes
иcamel-archetype-component
указывают, какой проект надо создать по шаблону, версия2.17.4
взята с учётом рантайма SAP CPI.demo.cpi
,coffee_comp
и0.0.1
это составное имя нового артефакта -- компонента Camel- scheme=
coffee
означает что наш компонент будет обрабатывать адреса видаcoffee://espresso
- name=
CpiCoffee
будет использован для создания файловCpiCoffee*.java
с логикой работы коннектора
Запустили, накачались артефакты и в случае успеха:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.1.2:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.1.2:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.1.2:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] Archetype repository not defined. Using the one from [org.apache.camel.archetypes:camel-archetype-component:3.3.0] found in catalog remote
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: camel-archetype-component:2.17.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: demo.cpi
[INFO] Parameter: artifactId, Value: coffee_comp
[INFO] Parameter: version, Value: 0.0.1
[INFO] Parameter: package, Value: demo.cpi
[INFO] Parameter: packageInPathFormat, Value: demo/cpi
[INFO] Parameter: name, Value: CpiCoffee
[INFO] Parameter: maven-bundle-plugin-version, Value: 2.3.7
[INFO] Parameter: scheme, Value: coffee
[INFO] Parameter: groupId, Value: demo.cpi
[INFO] Parameter: maven-resources-plugin-version, Value: 2.6
[INFO] Parameter: maven-compiler-plugin-version, Value: 3.5.1
[INFO] Parameter: slf4j-version, Value: 1.7.21
[INFO] Parameter: version, Value: 0.0.1
[INFO] Parameter: log4j-version, Value: 1.2.17
[INFO] Parameter: camel-version, Value: 2.17.4
[INFO] Parameter: package, Value: demo.cpi
[INFO] Parameter: artifactId, Value: coffee_comp
[INFO] Project created from Archetype in dir: C:\webinars\2020-06-02-cpiadapter\coffee_comp
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.183 s
[INFO] Finished at: 2020-05-31T12:04:05+03:00
[INFO] ------------------------------------------------------------------------
Файловая структура такая будет:
coffee_comp
│ pom.xml
│ ReadMe.txt
│
├───src
│ ├───data
│ ├───main
│ │ ├───java
│ │ │ └───demo
│ │ │ └───cpi
│ │ │ CpiCoffeeComponent.java
│ │ │ CpiCoffeeConsumer.java
│ │ │ CpiCoffeeEndpoint.java
│ │ │ CpiCoffeeProducer.java
│ │ │
│ │ └───resources
│ │ └───META-INF
│ │ └───services
│ │ └───org
│ │ └───apache
│ │ └───camel
│ │ └───component
│ │ coffee
│ │
│ └───test
│ ├───java
│ │ └───demo
│ │ └───cpi
│ │ CpiCoffeeComponentTest.java
│ │
│ └───resources
│ log4j.properties
│
└───target
coffee_comp-0.0.1.jar
Для экспериментов открываем этот проект в IdeaJ:
Open or Import, C:\webinars\2020-06-02-cpiadapter\coffee_comp
.
Запуск теста CpiCoffeeComponentTest.java
у вас явно пройдёт успешно, но для консольных примеров
мы напишем такой C:\webinars\2020-06-02-cpiadapter\coffee_comp\src\test\java\demo\cpi\Main.java
:
package demo.cpi;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
class WebinarDemo extends RouteBuilder {
@Override
public void configure() throws Exception {
from("coffee://x?name=espresso&option=1")
.to("coffee://y?option=2")
.to("file://tmp");
}
}
public class Main {
public static void main(String[] args) throws Exception {
CamelContext ctx = new DefaultCamelContext();
ctx.addRoutes(new WebinarDemo());
ctx.start();
Thread.sleep(5000);
ctx.stop();
}
}
Наша кофеварка будет периодически отправлять сообщения из coffee://x
в coffee://y
и файловую папку C:\webinars\2020-06-02-cpiadapter\coffee_comp\tmp
.
В данном примере по умолчанию мэвен-плагин создаёт Endpoint с параметрами:
- name (обязательный, строка). В нашем примере обязательность на Producer нарушена, но ошибка не возникает
- option (по умолчанию 10, число)
Штатно X и Y никуда не сохраняются, и чтобы их получать, впишем в CpiCoffeeEndpoint.java
новый параметр host с сеттером и геттером:
public class CpiCoffeeEndpoint extends DefaultEndpoint {
private String host = null;
void setHost(String host) {
this.host = host;
}
public String getHost() {
return host;
}
...
А в CpiCoffeeComponent.java
:
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
CpiCoffeeEndpoint endpoint = new CpiCoffeeEndpoint(uri, this); // меняем класс у endpoint, чтобы был виден setHost
setProperties(endpoint, parameters);
endpoint.setHost(remaining); // __добавляем руками__
return endpoint;
}
Как видим, стандартный UriEndpointComponent
передаёт полный путь в uri
, параметры в parameters
а неразобранный остаток в remaining
, который мы интерпретируем как host
.
Для настройки интервала опроса и формирования содержимого, пропишем в CpiCoffeeConsumer.java
:
public CpiCoffeeConsumer(CpiCoffeeEndpoint endpoint, Processor processor) {
super(endpoint, processor);
this.endpoint = endpoint;
this.setDelay(1000L); // интервал поллинга
}
@Override
protected int poll() throws Exception {
Exchange exchange = endpoint.createExchange();
// create a message body
Date now = new Date();
/* Вот это вписываем */
Message msg = exchange.getIn();
msg.setHeader("CoffeeStart", now.toString());
msg.setHeader("CoffeeName", endpoint.getName());
msg.setHeader("CoffeeHost", endpoint.getHost());
String s = MessageFormat.format("Coffee started: host={0} name={1} option={2} version={3}", endpoint.getHost(), endpoint.getName(), endpoint.getOption(), endpoint.getVersion());
msg.setBody(s);
exchange.setProperty("CoffeeVersion", endpoint.getVersion());
...
Отправитель-consumer шлёт сообщение, плюс три заголовка и Exchange-property CoffeeVersion
.
На стороне получателя-producer CpiCoffeeProducer.java
немного меняем метод получения, вместо System.out
:
public void process(Exchange exchange) throws Exception {
LOG.info(exchange.getIn().getBody().toString()); // выводим через sfl4j
// System.out.println(exchange.getIn().getBody()); было по шаблону
}
Теперь запуск Main.main()
отработает примерно так:
[ main] DefaultCamelContext INFO Apache Camel 2.17.4 (CamelContext: camel-1) is starting
[ main] ManagedManagementStrategy INFO JMX is enabled
[ main] DefaultTypeConverter INFO Loaded 184 type converters
[ main] DefaultRuntimeEndpointRegistry INFO Runtime endpoint registry is in extended mode gathering usage statistics of all incoming and outgoing endpoints (cache limit: 1000)
[ main] DefaultCamelContext INFO AllowUseOriginalMessage is enabled. If access to the original message is not needed, then its recommended to turn this option off as it may improve performance.
[ main] DefaultCamelContext INFO StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
[ main] DefaultCamelContext INFO Route: route1 started and consuming from: Endpoint[coffee://x?name=espresso&option=1]
[ main] DefaultCamelContext INFO Total 1 routes, of which 1 are started.
[ main] DefaultCamelContext INFO Apache Camel 2.17.4 (CamelContext: camel-1) started in 0.904 seconds
[amel-1) thread #0 - coffee://x] CpiCoffeeProducer INFO Coffee started: host=x name=espresso option=1 version=2.17.4
[amel-1) thread #0 - coffee://x] CpiCoffeeConsumer INFO Coffee consumer ID-MOWN34097792A-52631-1590921427160-0-2
[amel-1) thread #0 - coffee://x] CpiCoffeeProducer INFO Coffee started: host=x name=espresso option=1 version=2.17.4
[amel-1) thread #0 - coffee://x] CpiCoffeeConsumer INFO Coffee consumer ID-MOWN34097792A-52631-1590921427160-0-4
[amel-1) thread #0 - coffee://x] CpiCoffeeProducer INFO Coffee started: host=x name=espresso option=1 version=2.17.4
[amel-1) thread #0 - coffee://x] CpiCoffeeConsumer INFO Coffee consumer ID-MOWN34097792A-52631-1590921427160-0-6
[amel-1) thread #0 - coffee://x] CpiCoffeeProducer INFO Coffee started: host=x name=espresso option=1 version=2.17.4
[amel-1) thread #0 - coffee://x] CpiCoffeeConsumer INFO Coffee consumer ID-MOWN34097792A-52631-1590921427160-0-8
[ main] DefaultCamelContext INFO Apache Camel 2.17.4 (CamelContext: camel-1) is shutting down
[ main] DefaultShutdownStrategy INFO Starting to graceful shutdown 1 routes (timeout 300 seconds)
[el-1) thread #1 - ShutdownTask] DefaultShutdownStrategy INFO Route: route1 shutdown complete, was consuming from: Endpoint[coffee://x?name=espresso&option=1]
[ main] DefaultShutdownStrategy INFO Graceful shutdown of 1 routes completed in 0 seconds
[ main] DefaultCamelContext INFO Apache Camel 2.17.4 (CamelContext: camel-1) uptime 5.922 seconds
[ main] DefaultCamelContext INFO Apache Camel 2.17.4 (CamelContext: camel-1) is shutdown in 0.009 seconds
Process finished with exit code 0
В C:\webinars\2020-06-02-cpiadapter\coffee_comp\tmp\
появится 4-5 файлов с содержимым:
Coffee started: host=x name=espresso option=1 version=2.17.4
«Всё это хорошо, прекрасно», отвѣтилъ онъ: "но всё это меня что-то не веселитъ"
ADK в Eclipse
От прекрасного и понятного перейдём к ADK (Adapter Development Kit).
Создаём проект с параметрами:
Project Name = CpiCoffee
Adapter Details
Name = CpiCoffee
ID = CpiCoffee
Version = 1.0.0
Vendor = cpi.demo
[x] Enable Maven
Component Details
Name = CpiCoffee
Package = cpicoffee
Созданный проект (шаблон - см. com.sap.cloud.adk:com.sap.cloud.adk.build.archive:1.30.0
) в целом аналогичен
camel-archetype-component но есть ряд SAP-специфичных файлов:
CpiCofee
│ .classpath
│ .project
│ config.adk <-- файл со свойствами для ADK
│ pom.xml
│
├───src
│ ├───main
│ │ ├───java
│ │ │ └───cpicoffee
│ │ │ CpiCoffeeComponent.java
│ │ │ CpiCoffeeConsumer.java
│ │ │ CpiCoffeeEndpoint.java
│ │ │ CpiCoffeeProducer.java
│ │ │
│ │ └───resources
│ │ ├───META-INF
│ │ │ └───services
│ │ │ └───org
│ │ │ └───apache
│ │ │ └───camel
│ │ │ └───component
│ │ │ sap-sample <-- к сожалению, это имя зашито в плагине
│ │ │
│ │ └───metadata
│ │ metadata.xml
│ │
│ └───test
│ └───java
│ └───cpicoffee
│ CpiCoffeeComponentTest.java
│
└───target
Я рекомендую сравнить этот проект с набором файлов, созданным из camel-archetype-component
,
и внести некоторые изменения в SAP-вариант:
- Переименовать sap-sample в coffee а также ссылки на него в CpiCoffeeEndpoint.java, CpiCoffeeComponentTest.java, metadata.xml
- TODO
Ошибки и их причины
Blueprint metadata
[ERROR] Blueprint Metadata is not referred in the Component Metadata
[ERROR] Adapter build failed due to: Validation Failed: Blueprint Metadata is not referred in the Component Metadata
Необходимо декомпилировать com.sap.cloud.adk.build_1.30.0.jar
из плагина для Eclipse, и найти
\com\sap\cloud\adk\checks\AdapterProjectChecks.java
, метод isReferencedComponentPresentInMetadata
:
AdapterMetadataBuildUtil.getVariantIds -- из XML вытаскивает список /ComponentMetadata/Variant/@VariantId
List bpMetadataVariantIds = AdapterMetadataBuildUtil.getVariantIds(AdapterMetadataBuildUtil.getDocumentFromFile(bpMetadataFile));
ctype::AdapterVariant/cname::CpiCoffee2/vendor::cpi.demo/tp::sap-sample/mp::sap-sample/direction::Sender
ctype::AdapterVariant/cname::CpiCoffee2/vendor::cpi.demo/tp::sap-sample/mp::sap-sample/direction::Receiver
Точно в отладчике пока воспроизвести не смог но побороть получилось - просто удалить bpMetadata.xml с тем чтобы он создался заново при необходимости.
Ссылки
[1] Camel in action, второе издание, параграф 8.4 про разработку
[2] Запись видео /* TODO */
[3] Отличный пример по BlogADKAdapter - https://blogs.sap.com/2018/06/05/sap-cloud-platform-integration-new-adapter-api-for-adapter-development/
[4] Устаревший подход (до Maven) - https://blogs.sap.com/2017/06/23/extension-of-runtime-capabilities-using-blueprint-metadata-in-cloud-platform-integration-sdk/
[5] Developing Adapters, документация по CPI