Сгенерировать VDM для SFSF с помощью Java в SAP Cloud SDK: сгенерированный URI неверен
Я пытаюсь создать приложение, которое считывает информацию из SFSF. Для этого я использую инструмент генератора моделей виртуальных данных (плагин maven) с метаданными SFSF OData, чтобы иметь доступ к системе. Я выполняю следующие шаги:
- Получить проект через архетип (с помощью powershell):
mvn archetype:generate "-DarchetypeGroupId=com.sap.cloud.sdk.archetypes" "-DarchetypeArtifactId=scp-cf-tomee" "-DarchetypeVersion=RELEASE"
- Добавьте в приложение \pom.xml In dependencies следующее:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
В плагинах:
<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-generator-maven-plugin</artifactId>
<version>3.13.0</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/edmx</inputDirectory>
<outputDirectory>${project.build.directory}/vdm</outputDirectory>
<defaultBasePath>/odata/v2</defaultBasePath>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/vdm</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
- Получите файл метаданных OData из https://apisalesdemo2.successfactors.eu/odata/v2/JobRequisition/$metadata и поместите его в./application/edmx
- Создайте службу назначения (my-destination) и добавьте туда пункт назначения, указывающий на мой экземпляр SFSF с базовой аутентификацией (с user @companyId, соединение 200:OK)
- Добавьте целевой сервис в manifest.yml
- Создайте класс java для вызова пункта назначения и получения данных:
package com.sap.sdk;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.s4hana.connectivity.DefaultErpHttpDestination;
import com.sap.cloud.sdk.s4hana.connectivity.ErpHttpDestination;
import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.rcmjobrequisition.JobRequisition;
import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultRCMJobRequisitionService;
@WebServlet("/req")
public class JobReqServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(JobReqServlet.class);
private final ErpHttpDestination destination = DestinationAccessor.getDestination("sfsf-sdk-dest").asHttp()
.decorate(DefaultErpHttpDestination::new);
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
try {
final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
.getAllJobRequisition()
.execute(destination);
response.setContentType("application/json");
response.getWriter().write(new Gson().toJson(jobReqs));
} catch (final ODataException e) {
logger.error(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write(e.getMessage());
}
}
}
При всем этом (думаю, я ничего не упускаю) я делаю:
mvn clean install
а также:
cf push
Все работает хорошо, сервлет hello world работает, но когда я пытаюсь получить доступ к /req, я получаю: Невозможно выполнить запрос метаданных.
Однако я вижу, что приложение попадает в SFSF, потому что, если я играю с базовым путем к службе (в pom.xml), я получаю 404 от SFSF.
Проверяя все, я вижу это при работающем генераторе VDM: 1. Это базовый путь, который я даю в pom:
<defaultBasePath>/odata/v2</defaultBasePath>
- Я вижу, как генератор правильно выбирает этот путь:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.DataModelGenerator - Default base path: /odata/v2/
- Но вот что обрабатывает генератор:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Title: RCMJobRequisition
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Raw URL: /odata/v2/SFODataSet
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Java Package Name: rcmjobrequisition
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Java Class Name: RCMJobRequisition
Ясно, что SFODataSet в URL неверен. Когда приложение запускается, ему нужно получить метаданные из.../odata/v2/SFODataSet/$metadata, и поэтому оно не находит их. Этот SFODataSet исходит из метаданных SFSF:
<Schema Namespace="SFODataSet" xmlns="http://schemas.microsoft.com/ado/2008/09/edm" xmlns:sf="http://www.successfactors.com/edm/sf" xmlns:sap="http://www.sap.com/Protocols/SAPData">
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
<EntitySet Name="JobOfferTemplate_Standard_Offer_Details" EntityType="SFOData.JobOfferTemplate_Standard_Offer_Details" sap:label="JobOfferTemplate_Standard_Offer_Details" sap:creatable="false" sap:updatable="false" sap:upsertable="false" sap:deletable="false">
<Documentation>
<Summary>Job Requisition Template</Summary>
<LongDescription>These entities represent the job requisition template as defined in provisioning.</LongDescription>
<sap:tagcollection>
<sap:tag>Recruiting (RCM)</sap:tag>
<sap:tag>RCM - Job Requisition</sap:tag>
</sap:tagcollection>
</Documentation>
</EntitySet>
<EntitySet Name="JobRequisitionLocale" EntityType="SFOData.JobRequisitionLocale" sap:label="JobRequisitionLocale" sap:creatable="false" sap:updatable="false" sap:upsertable="false" sap:deletable="false">
<Documentation>
...
Я не могу найти способ, чтобы это сработало. Вы можете помочь мне найти здесь проблему?
Я использую:
- Apache Maven 3.6.2
- SAP Cloud SDK 3.13.0
Изменить: файлы метаданных SFSF доступны на https://api.sap.com/ Тот, который я использую для этого приложения, предназначен для SFSF - Job Requisition, доступный здесь: https://api.sap.com/api/RCMJobRequisition/overview
Оттуда вы можете скачать спецификацию EDMX. Это "фиктивные" API, не связанные с реальным экземпляром SFSF, но проблема та же.
Для этого я в основном слежу за двумя блогами:
- https://blogs.sap.com/2018/04/30/deep-dive-10-with-sap-s4hana-cloud-sdk-generating-java-vdm-for-s4hana-custom-odata-service/
- https://blogs.sap.com/2019/05/06/create-an-application-with-sap-cloud-sdk-to-integrate-with-sap-successfactors/
Кроме того, я удалил последнюю часть, так как открою отдельный вопрос: Вызов SFSF OData: не удалось преобразовать ответ в ODataFeed: произошло исключение EdmSimpleTypeException
Спасибо,
Kepair
1 ответ
Я начну с частичного ответа и при необходимости отредактирую дополнительную информацию позже.
Что касается URL:
Наблюдаемое вами поведение является преднамеренным. Полный URL-адрес запроса будет составлен следующим образом: URL-адрес назначения + путь к службе + имя службы + объект + '?' + параметры запроса. Итак, в вашем случае это может быть:
https://my.host.domain/odata/v2/JobRequisitions/MyEntity
Destination: https://my.host.domain
Service Path: /odata/v2
Service name: JobRequisitions
Entity: MyEntity
Генератор собирает базовый путь по умолчанию из service path + service name
. Вservice name
фактически будет извлечен из пространства имен EDMX. Вот почему URL-адрес вашей службы создается так, как есть.
Причина этого проста: можно создать VDM для нескольких служб одновременно. Все эти службы доступны в одной конечной точке, за исключением самого имени службы. Чтобы сгенерировать все VDM с одной конфигурацией, мы можем указать "путь службы" в генераторе, и генератор извлекает имя службы из самого EDXM.
Это означает, что ваш подход к перезаписи сгенерированного базового пути должен работать:
final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
.withServicePath("odata/v2/JobRequisition")
.getAllJobRequisition()
.execute(destination);
Сообщение об ошибке в самом конце вашего вопроса для меня немного похоже на проблему с синтаксическим анализом. Но для того, чтобы решить эту проблему, нам потребуются полная трассировка стека и вывод журнала HTTP. Кроме того, мы можем воспроизвести проблему, только если у нас есть доступ к метаданным. Указанная вами ссылка требует авторизации через имя пользователя / пароль.
Поскольку ваш вопрос выше уже достаточно всеобъемлющий, я бы порекомендовал вам разделить эти две проблемы и создать новый вопрос, если это действительно окажется независимой проблемой. Это также сделает оба вопроса более актуальными для других.