Skip to content

Commit

Permalink
Merge pull request #443 from FraunhoferISST/feat/erpadapter_request
Browse files Browse the repository at this point in the history
Feat/erpadapter request client
  • Loading branch information
tom-rm-meyer-ISST authored Jun 20, 2024
2 parents 7c7f4cf + 234e4fb commit 8263810
Show file tree
Hide file tree
Showing 18 changed files with 545 additions and 206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ private void setupCustomerRole() throws JsonProcessingException {
.directionCharacteristic(DirectionCharacteristic.INBOUND)
.requestType("ItemStock")
.sammVersion("2.0")
.responseCode(201)
.build();
mockRequest = erpAdapterRequestService.create(mockRequest);
log.info("Created mocked ErpAdapterRequest: \n{}", mockRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,6 @@ public JsonNode buildProxyPullRequestBody(Partner partner, String contractID, St
dataDestination.put("type", "HttpProxy");
body.set("dataDestination", dataDestination);

// This private property is not evaluated in EDC 0.7.0 anymore due to data plane signalling
// EDRs are taken manually
var privateProperties = MAPPER.createObjectNode();
privateProperties.put("receiverHttpEndpoint", variablesService.getEdrEndpoint());
body.set("privateProperties", privateProperties);

log.debug("Built Proxy Pull Request:\n{}", body.toPrettyString());
return body;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


@Getter
@Service
/**
Expand All @@ -42,6 +41,14 @@ public class VariablesService {
@Value("${puris.baseurl}")
private String purisBaseUrl;

/**
* The puris base url as defined in the property puris.baseurl,
* ending with a slash ('/').
*/
public String getPurisBaseUrl() {
return purisBaseUrl.endsWith("/") ? purisBaseUrl : purisBaseUrl + "/";
}

@Value("${puris.demonstrator.role}")
/**
* Must be set to "CUSTOMER" or "SUPPLIER" if
Expand All @@ -50,18 +57,24 @@ public class VariablesService {
*/
private String demoRole;

@Value("${puris.baseurl}" + "catena/edrendpoint")
@Value("${server.servlet.context-path}")
private String contextPath;

/**
* The edrEndpoint to be used during consumer pull asset transfers.
* The context path as defined in the property server.servlet.context-path,
* ending with a slash ('/').
*/
private String edrEndpoint;
public String getContextPath() {
return contextPath.replace("/", "") + "/";
}

@Value("${puris.baseurl}" + "catena/item-stock/request")
/**
* The url under which this application's request endpoint can
* The url under which this application's item stock request endpoint can
* be reached by external machines.
*/
private String itemStockSubmodelEndpoint;
public String getItemStockSubmodelEndpoint() {
return getPurisBaseUrl() + getContextPath() + "item-stock/request";
}

@Value("${puris.itemstocksubmodel.apiassetid}")
/**
Expand All @@ -70,12 +83,13 @@ public class VariablesService {
*/
private String itemStockSubmodelAssetId;

@Value("${puris.baseurl}" + "catena/planned-production/request")
/**
* The url under which this application's request endpoint can
* The url under which this application's planned production request endpoint can
* be reached by external machines.
*/
private String productionSubmodelEndpoint;
public String getProductionSubmodelEndpoint() {
return getPurisBaseUrl() + getContextPath() + "planned-production/request";
}

@Value("${puris.productionsubmodel.apiassetid}")
/**
Expand All @@ -84,12 +98,13 @@ public class VariablesService {
*/
private String productionSubmodelAssetId;

@Value("${puris.baseurl}" + "catena/material-demand/request")
/**
* The url under which this application's request endpoint can
* The url under which this application's material demand request endpoint can
* be reached by external machines.
*/
private String demandSubmodelEndpoint;
public String getDemandSubmodelEndpoint() {
return getPurisBaseUrl() + getContextPath() + "material-demand/request";
}

@Value("${puris.demandsubmodel.apiassetid}")
/**
Expand All @@ -98,12 +113,13 @@ public class VariablesService {
*/
private String demandSubmodelAssetId;

@Value("${puris.baseurl}" + "catena/delivery-information/request")
/**
* The url under which this application's request endpoint can
* The url under which this application's delivery information request endpoint can
* be reached by external machines.
*/
private String deliverySubmodelEndpoint;
public String getDeliverySubmodelEndpoint() {
return getPurisBaseUrl() + getContextPath() + "delivery-information/request";
}

@Value("${puris.deliverysubmodel.apiassetid}")
/**
Expand Down Expand Up @@ -148,8 +164,13 @@ public class VariablesService {
*/
private String dtrUrl;

@Value("${puris.baseurl}" + "catena/parttypeinformation")
private String parttypeInformationServerendpoint;
/**
* The url under which this application's part type request endpoint can
* be reached by external machines.
*/
public String getParttypeInformationServerendpoint() {
return getPurisBaseUrl() + getContextPath() + "parttypeinformation";
}

@Value("${puris.generatematerialcatenaxid}")
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.eclipse.tractusx.puris.backend.erpadapter;

import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
@Getter
public class ErpAdapterConfiguration {

/**
* Toggles usage of the ERP adapter
*/
@Value("${puris.erpadapter.enabled}")
private boolean erpAdapterEnabled;

/**
* The URL of the ERP adapter
*/
@Value("${puris.erpadapter.url}")
private String erpAdapterUrl;

/**
* The URL under which we expect responses from
* the ERP adapter
*/
@Value("${puris.baseurl}" + "${server.servlet.context-path}" + "/erp-adapter")
private String erpResponseUrl;

/**
* The auth-key used when accessing the ERP adapter's
* request interface
*/
@Value("${puris.erpadapter.authkey}")
private String erpAdapterAuthKey;

/**
* The auth-secret used when accessing the ERP adapter's
* request interface
*/
@Value("${puris.erpadapter.authsecret}")
private String erpAdapterAuthSecret;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public class ErpAdapterRequest {
@NotNull
private Date requestDate;

private Integer responseCode;

private Date responseReceivedDate;

@Pattern(regexp = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_STRING)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2024 Volkswagen AG
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.eclipse.tractusx.puris.backend.erpadapter.logic.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.eclipse.tractusx.puris.backend.erpadapter.ErpAdapterConfiguration;
import org.eclipse.tractusx.puris.backend.erpadapter.domain.model.ErpAdapterRequest;
import org.springframework.stereotype.Service;

import java.io.IOException;

@Service
@Slf4j
@RequiredArgsConstructor
public class ErpAdapterRequestClient {

private final OkHttpClient client = new OkHttpClient();

private final ObjectMapper mapper = new ObjectMapper();

private final ErpAdapterConfiguration erpAdapterConfiguration;

public Integer sendRequest(ErpAdapterRequest erpAdapterRequest){
HttpUrl.Builder urlBuilder = HttpUrl.parse(erpAdapterConfiguration.getErpAdapterUrl()).newBuilder();
urlBuilder.addQueryParameter("bpnl", erpAdapterRequest.getPartnerBpnl());
urlBuilder.addQueryParameter("request-type", erpAdapterRequest.getRequestType());
urlBuilder.addQueryParameter("request-id", erpAdapterRequest.getId().toString());
urlBuilder.addQueryParameter("samm-version", erpAdapterRequest.getSammVersion());
urlBuilder.addQueryParameter("request-timestamp", String.valueOf(erpAdapterRequest.getRequestDate().getTime()));

ObjectNode requestBody = mapper.createObjectNode();

requestBody.put("material", erpAdapterRequest.getOwnMaterialNumber());
requestBody.put("direction", erpAdapterRequest.getDirectionCharacteristic().toString());
requestBody.put("responseUrl", erpAdapterConfiguration.getErpResponseUrl());

RequestBody body = RequestBody.create(requestBody.toString(), MediaType.parse("application/json"));

Request request = new Request.Builder()
.post(body)
.url(urlBuilder.build())
.header(erpAdapterConfiguration.getErpAdapterAuthKey(), erpAdapterConfiguration.getErpAdapterAuthSecret())
.header("Content-Type", "application/json")
.build();
try (var response = client.newCall(request).execute()) {
return response.code();
} catch (IOException e) {
log.error("Error while sending ErpAdapterRequest", e);
return null;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,49 @@

package org.eclipse.tractusx.puris.backend.erpadapter.logic.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.tractusx.puris.backend.erpadapter.domain.model.ErpAdapterRequest;
import org.eclipse.tractusx.puris.backend.erpadapter.domain.repository.ErpAdapterRequestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
@Slf4j
@RequiredArgsConstructor
public class ErpAdapterRequestService {

@Autowired
private ErpAdapterRequestRepository repository;
private final ErpAdapterRequestRepository repository;

private final ErpAdapterRequestClient erpAdapterRequestClient;

public ErpAdapterRequest create(ErpAdapterRequest erpAdapterRequest) {
if (erpAdapterRequest.getId() != null && repository.existsById(erpAdapterRequest.getId())) {
log.error("ErpAdapterRequest with id {} already exists", erpAdapterRequest.getId());
return null;
}
return repository.save(erpAdapterRequest);
}

public void createAndSend(ErpAdapterRequest erpAdapterRequest) {
erpAdapterRequest = create(erpAdapterRequest);
if (erpAdapterRequest != null) {
Integer responseCode = erpAdapterRequestClient.sendRequest(erpAdapterRequest);
if (responseCode != null) {
if (responseCode >= 200 && responseCode < 400) {
log.info("Successfully sent request to ERP Adapter, got status code {} for request:\n{}", responseCode, erpAdapterRequest);
} else {
log.warn("Received status code {} from ERP Adapter for request:\n{}", responseCode, erpAdapterRequest);
}
erpAdapterRequest.setResponseCode(responseCode);
update(erpAdapterRequest);
} else {
log.error("Failed to send request to ERP Adapter:\n{}", erpAdapterRequest);
}
}
}

public ErpAdapterRequest get(UUID id) {
// TODO: Remove when mock is removed
return repository.findById(id).orElse(repository.findAll().getFirst());
Expand All @@ -50,6 +73,7 @@ public ErpAdapterRequest update(ErpAdapterRequest erpAdapterRequest) {
if (repository.existsById(erpAdapterRequest.getId())) {
return repository.save(erpAdapterRequest);
}
log.error("ErpAdapterRequest with id {} did not exist, could not update entity", erpAdapterRequest.getId());
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public int receiveItemStockUpdate(ErpAdapterController.Dto dto) {
// log.error("Received duplicate response for messageId {}", request.getId());
// return 409;
// }
if (request.getResponseCode() == null || request.getResponseCode() < 200 || request.getResponseCode() >= 400) {
log.error("Unexpected response, erp adapter had not confirmed request");
return 404;
}
if (!request.getPartnerBpnl().equals(dto.partnerBpnl())) {
log.error("BPNL mismatch! request BPNL: {}, message BPNL: {}",
request.getPartnerBpnl(), dto.partnerBpnl());
Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ puris.dtr.idp.edc-client.id=${PURIS_DTR_IDP_EDC-CLIENT_ID:FOSS-DTR-CLIENT}
puris.dtr.idp.edc-client.secret.alias=${PURIS_DTR_IDP_EDC-CLIENT_SECRET_ALIAS}
puris.dtr.idp.puris-client.id=${PURIS_DTR_IDP_PURIS-CLIENT_ID:FOSS-DTR-CLIENT}
puris.dtr.idp.puris-client.secret=${PURIS_DTR_IDP_PURIS-CLIENT_SECRET}
puris.erpadapter.enabled=${PURIS_ERPADAPTER_ENABLED:false}
puris.erpadapter.url=${PURIS_ERPADAPTER_URL:http://my-erpadapter:8080}
puris.erpadapter.authkey=${PURIS_ERPADAPTER_AUTHKEY:x-api-key}
puris.erpadapter.authsecret=${PURIS_ERPADAPTER_AUTHSECRET:erp-password}
# Flag that decides whether the auto-generation feature of the puris backend is enabled.
# Since all Material entities are required to have a CatenaX-Id, you must enter any pre-existing CatenaX-Id
# via the materials-API of the backend, when you are inserting a new Material entity to the backend's
Expand Down
Loading

0 comments on commit 8263810

Please sign in to comment.