From 8735f27d3ddcf93d369705c50443f028f1266ff8 Mon Sep 17 00:00:00 2001 From: Mathias Schmoigl Date: Tue, 18 Jun 2019 16:06:18 +0200 Subject: [PATCH 1/2] added API for ERP integration, work in progress --- .../datachannel/controller/ErpAPI.java | 106 +++++++++++++ .../datachannel/controller/ErpController.java | 145 ++++++++++++++++++ .../entity/ChannelConfiguration.java | 24 +++ .../entity/ERPData/SensorValue.java | 42 +++++ 4 files changed, 317 insertions(+) create mode 100644 data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpAPI.java create mode 100644 data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpController.java create mode 100644 data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ERPData/SensorValue.java diff --git a/data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpAPI.java b/data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpAPI.java new file mode 100644 index 0000000..b0b0ed7 --- /dev/null +++ b/data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpAPI.java @@ -0,0 +1,106 @@ +package eu.nimble.service.datachannel.controller; + +import com.mashape.unirest.http.exceptions.UnirestException; +import eu.nimble.service.datachannel.entity.ERPData.SensorValue; +import io.swagger.annotations.*; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@Api(value = "ERP", description = "ERP integration API") +public interface ErpAPI { + + /** + * See API documentation + * + * @param bearer OpenID Connect token storing requesting identity + * @return See API documentation + * @throws UnirestException Error while communication with the Identity Service + */ + @ApiOperation(value = "Get all registered negotiation channels", nickname = "getAllActiveChannels") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Received all Nimble Channel IDs", response = Object.class), + @ApiResponse(code = 400, message = "Error while getting Nimble Channel IDs"), + @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found") }) + @RequestMapping(value = "/getAllActiveChannels", produces = {"application/json"}, method = RequestMethod.GET) + ResponseEntity getAllActiveChannels( + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) + throws UnirestException; + + /** + * See API documentation + * + * @param channelID Nimble Channel ID + * @param bearer OpenID Connect token storing requesting identity + * @return See API documentation + * @throws UnirestException Error while communication with the Identity Service + */ + @ApiOperation(value = "Get config data for channel negotiation", nickname = "getConfigDataForChannel") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Received specific Nimble Channel Data", response = Object.class), + @ApiResponse(code = 400, message = "Error while getting Nimble Channel Data"), + @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found") }) + @RequestMapping(value = "/getConfigData/{channelID}", produces = {"application/json"}, method = RequestMethod.GET) + ResponseEntity getConfigData( + @ApiParam(value = "channelID", required = true) + @PathVariable String channelID, + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) + throws UnirestException; + + /** + * See API documentation + * + * @param sensorValueMap sensor data object + * @param channelID Nimble Channel ID + * @param bearer OpenID Connect token storing requesting identity + * @return See API documentation + * @throws UnirestException Error while communication with the Identity Service + */ + @ApiOperation(value = "Produce sensor data for channel negotiation", nickname = "produceSensorData") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Sensor Data produced", response = Object.class), + @ApiResponse(code = 400, message = "Error while producing sensor data"), + @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found") }) + @RequestMapping(value = "/produceSensorData/{channelID}", consumes = {"application/json"}, method = RequestMethod.POST) + ResponseEntity produceSensorData( + @ApiParam(value = "erp data", required = true) + @RequestBody Map sensorValueMap, + @ApiParam(value = "channelID", required = true) + @PathVariable String channelID, + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) + throws UnirestException; + + /** + * See API documentation + * + * @param channelID Nimble Channel ID + * @param bearer OpenID Connect token storing requesting identity + * @return See API documentation + * @throws UnirestException Error while communication with the Identity Service + */ + @ApiOperation(value = "Consume sensor data for channel negotiation", nickname = "consumeSensorData", response = Map.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Sensor Data consumed", response = Object.class), + @ApiResponse(code = 400, message = "Error while consuming sensor data"), + @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse(code = 403, message = "Forbidden"), + @ApiResponse(code = 404, message = "Not Found") }) + @RequestMapping(value = "/consumeSensorData/{channelID}", consumes = {"application/json"}, method = RequestMethod.GET) + ResponseEntity consumeSensorData( + @ApiParam(value = "channelID", required = true) + @PathVariable String channelID, + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) + throws UnirestException; +} diff --git a/data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpController.java b/data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpController.java new file mode 100644 index 0000000..6f2a7dc --- /dev/null +++ b/data-channel-service/src/main/java/eu/nimble/service/datachannel/controller/ErpController.java @@ -0,0 +1,145 @@ +package eu.nimble.service.datachannel.controller; + +import com.mashape.unirest.http.exceptions.UnirestException; +import eu.nimble.common.rest.identity.IdentityResolver; +import eu.nimble.service.datachannel.entity.ChannelConfiguration; +import eu.nimble.service.datachannel.entity.ERPData.SensorValue; +import eu.nimble.service.datachannel.entity.Server; +import eu.nimble.service.datachannel.repository.ChannelConfigurationRepository; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * REST Controller for managing calls from ERP. + * + * @author Mathias Schmoigl + */ +@Controller +@RequestMapping(path = "/erp") +@Api("ERP Integration API") +public class ErpController implements ErpAPI { + + @Autowired + private IdentityResolver identityResolver; + + @Autowired + private ChannelConfigurationRepository channelConfigurationRepository; + + //-------------------------------------------------------------------------------------- + // getAllActiveChannels + //-------------------------------------------------------------------------------------- + public ResponseEntity getAllActiveChannels( + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) throws UnirestException { + + // extract ID of company + String companyID = identityResolver.resolveCompanyId(bearer); + + // get associated channels + Set sellerChannels = channelConfigurationRepository.findBySellerCompanyID(companyID); + Set buyerChannels = channelConfigurationRepository.findByBuyerCompanyID(companyID); + Map resultChannels = new HashMap(); + + // return if no channels found + if (sellerChannels == null || buyerChannels == null) { + return ResponseEntity.notFound().build(); + } + + // search and group sellers + for (ChannelConfiguration config : sellerChannels) { + if (config.isOnLastPage() && config.isChannelOpened()) { + resultChannels.put("seller", config.getChannelID()); + } + } + + // search and group buyers + for (ChannelConfiguration config : buyerChannels) { + if (config.isOnLastPage() && config.isChannelOpened()) { + resultChannels.put("buyer", config.getChannelID()); + } + } + + // return all found buyer and seller datachannels that are ready to be streamed + return ResponseEntity.ok(resultChannels); + } + + //-------------------------------------------------------------------------------------- + // getConfigData (for ChannelID) + //-------------------------------------------------------------------------------------- + public ResponseEntity getConfigData( + @ApiParam(value = "channelID", required = true) + @PathVariable String channelID, + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) throws UnirestException { + + ChannelConfiguration channelConfiguration = channelConfigurationRepository.findOneByChannelID(channelID); + if (channelConfiguration == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(channelConfiguration); + } + + //-------------------------------------------------------------------------------------- + // produceSensorData (for ChannelID) + //-------------------------------------------------------------------------------------- + public ResponseEntity produceSensorData( + @ApiParam(value = "erp data", required = true) + @RequestBody Map sensorValueMap, + @ApiParam(value = "channelID", required = true) + @PathVariable String channelID, + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) throws UnirestException { + + ChannelConfiguration channelConfiguration = channelConfigurationRepository.findOneByChannelID(channelID); + if (channelConfiguration == null) { + return ResponseEntity.notFound().build(); + } + + // produce data for every negotiated server + for(Server server: channelConfiguration.getAssociatedServers()) + { + // TODO: send SensorValues to all configured servers + // TODO: URL = jdbc:postgresql://${DATACHANNEL_DB_HOST:localhost}:${DATACHANNEL_DB_HOST_PORT:5432}/${DATACHANNEL_DB_NAME:sensordatadb} + } + + // if sending to all servers worked, return true + return ResponseEntity.ok(true); + } + + //-------------------------------------------------------------------------------------- + // consumeSensorData (for ChannelID) + //-------------------------------------------------------------------------------------- + public ResponseEntity consumeSensorData( + @ApiParam(value = "channelID", required = true) + @PathVariable String channelID, + @ApiParam(name = "Authorization", value = "OpenID Connect token containing identity of requester", required = true) + @RequestHeader(value = "Authorization") String bearer) throws UnirestException { + + ChannelConfiguration channelConfiguration = channelConfigurationRepository.findOneByChannelID(channelID); + if (channelConfiguration == null) { + return ResponseEntity.notFound().build(); + } + + // try to consume data from a negotiated server, try next if failed + for(Server server: channelConfiguration.getAssociatedServers()) { + + // TODO: receive SensorValues from first available server + // TODO: URL = jdbc:postgresql://${DATACHANNEL_DB_HOST:localhost}:${DATACHANNEL_DB_HOST_PORT:5432}/${DATACHANNEL_DB_NAME:sensordatadb} + } + + // if no server provided data, return false + return ResponseEntity.ok(false); + } +} diff --git a/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ChannelConfiguration.java b/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ChannelConfiguration.java index d79b4a1..e8281ef 100644 --- a/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ChannelConfiguration.java +++ b/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ChannelConfiguration.java @@ -218,4 +218,28 @@ public void setAssociatedNegotiationHistory(Set associatedNe this.associatedNegotiationHistory = associatedNegotiationHistory; } + @JsonIgnore + public boolean isOnLastPage() { + return negotiationStepcounter % 5 == 3; + } + + @JsonIgnore + public boolean isChannelOpened() + { + if (startDateTime == null) { + return false; + } + + if (endDateTime == null) { + return true; + } + + if (startDateTime.after(endDateTime)) { + return true; + } + else { + return false; + } + } + } diff --git a/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ERPData/SensorValue.java b/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ERPData/SensorValue.java new file mode 100644 index 0000000..21b1673 --- /dev/null +++ b/data-channel-service/src/main/java/eu/nimble/service/datachannel/entity/ERPData/SensorValue.java @@ -0,0 +1,42 @@ +package eu.nimble.service.datachannel.entity.ERPData; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@Entity +@ApiModel(value = "SensorValue") +public class SensorValue { + + @Id + @JsonIgnore + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @NotNull + @ApiModelProperty(value = "Value of sensor datum") + private Integer sensorValue; + + @NotNull + @Temporal(TemporalType.TIMESTAMP) + @ApiModelProperty(value = "Timestamp of sensor datum") + private java.util.Date sensorTime; + + + public Integer getSensorValue() { + return sensorValue; + } + public void setSensorValue(Integer value) { + this.sensorValue = value; + } + + public java.util.Date getSensorTime() { + return sensorTime; + } + public void setSensorTime(java.util.Date time) { + this.sensorTime = time; + } +} From e7fbc34f6bf1709697372af300f61546c3e90b10 Mon Sep 17 00:00:00 2001 From: Dileepa Jayakody Date: Mon, 29 Jul 2019 17:48:52 +0200 Subject: [PATCH 2/2] NIMBLEFMP-844 : fixing swagger request url endpoint --- .../service/datachannel/config/SwaggerConfig.java | 11 ++++++++++- data-channel-service/src/main/resources/bootstrap.yml | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/data-channel-service/src/main/java/eu/nimble/service/datachannel/config/SwaggerConfig.java b/data-channel-service/src/main/java/eu/nimble/service/datachannel/config/SwaggerConfig.java index 4cb79bf..88a4688 100644 --- a/data-channel-service/src/main/java/eu/nimble/service/datachannel/config/SwaggerConfig.java +++ b/data-channel-service/src/main/java/eu/nimble/service/datachannel/config/SwaggerConfig.java @@ -1,5 +1,6 @@ package eu.nimble.service.datachannel.config; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.PathSelectors; @@ -13,9 +14,17 @@ @Configuration @EnableSwagger2 public class SwaggerConfig { + + @Value("${nimble.platformHost}") + private String platformHost; @Bean public Docket api() { + + platformHost = platformHost.replace("https://", ""); + platformHost = platformHost.replace("http://",""); + return new Docket(DocumentationType.SWAGGER_2) + .host(platformHost) .select() .apis(RequestHandlerSelectors.basePackage("eu.nimble")) .paths(PathSelectors.any()) @@ -33,4 +42,4 @@ private ApiInfo metaData() { "Apache License Version 2.0", "https://www.apache.org/licenses/LICENSE-2.0"); } -} \ No newline at end of file +} diff --git a/data-channel-service/src/main/resources/bootstrap.yml b/data-channel-service/src/main/resources/bootstrap.yml index 823fb01..f2462de 100755 --- a/data-channel-service/src/main/resources/bootstrap.yml +++ b/data-channel-service/src/main/resources/bootstrap.yml @@ -42,6 +42,7 @@ nimble: identity-url: ${IDENTITY_SERVICE_URL:http://localhost:9092} kafka-domain: service-url: ${KAFKA_DOMAIN_URL:http://localhost:1000} + platformHost: ${DATA_CHANNEL_SERVICE_URL:http://localhost:9099} logging: level: @@ -87,4 +88,4 @@ spring: url: jdbc:h2:mem:channeldb initialize: false username: sa - password: \ No newline at end of file + password: