Skip to content

Commit

Permalink
feat: add API for the BPN validation extension (#688)
Browse files Browse the repository at this point in the history
* feat: add BPN group API

* renamed store

* javadoc

* cleanup

* add api and controller

* update license headers

* add test tag

* DEPENDENCIES
  • Loading branch information
paullatzelsperger authored Aug 4, 2023
1 parent d8b54dd commit 8670f2c
Show file tree
Hide file tree
Showing 30 changed files with 663 additions and 57 deletions.
6 changes: 3 additions & 3 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ maven/mavencentral/com.github.docker-java/docker-java-transport/3.3.0, Apache-2.
maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949
maven/mavencentral/com.google.code.findbugs/jsr305/3.0.2, Apache-2.0, approved, #20
maven/mavencentral/com.google.code.gson/gson/2.10.1, Apache-2.0, approved, #6159
maven/mavencentral/com.google.crypto.tink/tink/1.10.0, , restricted, clearlydefined
maven/mavencentral/com.google.crypto.tink/tink/1.10.0, Apache-2.0, approved, #9845
maven/mavencentral/com.google.errorprone/error_prone_annotations/2.18.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.google.errorprone/error_prone_annotations/2.7.1, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.google.guava/failureaccess/1.0.1, Apache-2.0, approved, CQ22654
Expand Down Expand Up @@ -340,7 +340,7 @@ maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.15, EPL-2.0 OR Apache-2.
maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty
maven/mavencentral/org.eclipse.jetty/jetty-webapp/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty
maven/mavencentral/org.eclipse.jetty/jetty-xml/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty
maven/mavencentral/org.flywaydb/flyway-core/9.21.1, , restricted, clearlydefined
maven/mavencentral/org.flywaydb/flyway-core/9.21.1, Apache-2.0, approved, #9846
maven/mavencentral/org.glassfish.hk2.external/aopalliance-repackaged/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish
maven/mavencentral/org.glassfish.hk2/hk2-api/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish
maven/mavencentral/org.glassfish.hk2/hk2-locator/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish
Expand Down Expand Up @@ -393,7 +393,7 @@ maven/mavencentral/org.junit.platform/junit-platform-engine/1.10.0, EPL-2.0, app
maven/mavencentral/org.junit.platform/junit-platform-engine/1.9.3, EPL-2.0, approved, #3128
maven/mavencentral/org.junit.platform/junit-platform-launcher/1.10.0, EPL-2.0, approved, #9704
maven/mavencentral/org.junit.platform/junit-platform-launcher/1.9.3, EPL-2.0, approved, #3132
maven/mavencentral/org.junit/junit-bom/5.10.0, , restricted, clearlydefined
maven/mavencentral/org.junit/junit-bom/5.10.0, EPL-2.0, approved, #9844
maven/mavencentral/org.junit/junit-bom/5.9.2, EPL-2.0, approved, #4711
maven/mavencentral/org.junit/junit-bom/5.9.3, EPL-2.0, approved, #4711
maven/mavencentral/org.jvnet.mimepull/mimepull/1.9.15, CDDL-1.1 OR GPL-2.0-only WITH Classpath-exception-2.0, approved, CQ21484
Expand Down
31 changes: 31 additions & 0 deletions edc-extensions/bpn-validation/bpn-validation-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

plugins {
`java-library`
`maven-publish`
id("io.swagger.core.v3.swagger-gradle-plugin")
}

dependencies {
implementation(project(":edc-extensions:bpn-validation:bpn-validation-spi"))
implementation(project(":spi:core-spi"))
implementation(libs.edc.api.management)
implementation(libs.edc.spi.aggregateservices)
implementation(libs.jakarta.rsApi)

testImplementation(testFixtures(libs.edc.core.jersey))
testImplementation(libs.restAssured)
testImplementation(libs.edc.junit)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft
*
* 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.edc.api.bpn;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.json.JsonObject;
import org.eclipse.edc.web.spi.ApiErrorDetail;

import java.util.Set;

import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;

@OpenAPIDefinition(info = @Info(description = "With this API clients can create, read, update and delete BusinessPartnerNumber groups. It allows the assigning of BPNs to groups.", title = "Business Partner Group API"))
@Tag(name = "BusinessPartnerGroup")
public interface BusinessPartnerGroupApi {


@Operation(description = "Resolves all groups for a particular BPN",
responses = {
@ApiResponse(responseCode = "200", description = "An object containing an array with the assigned groups"),
@ApiResponse(responseCode = "404", description = "No entry for the given BPN was found"),
@ApiResponse(responseCode = "400", description = "Request body was malformed",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class))))
})
JsonObject resolve(@Parameter(name = "bpn", description = "The business partner number") String bpn);

@Operation(description = "Deletes the entry for a particular BPN",
responses = {
@ApiResponse(responseCode = "204", description = "The object was successfully deleted"),
@ApiResponse(responseCode = "404", description = "No entry for the given BPN was found"),
@ApiResponse(responseCode = "400", description = "Request body was malformed",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class))))
})
void deleteEntry(@Parameter(name = "bpn", description = "The business partner number") String bpn);

@Operation(description = "Updates the entry for a particular BPN",
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = ListSchema.class))),

responses = {
@ApiResponse(responseCode = "204", description = "The object was successfully updated"),
@ApiResponse(responseCode = "404", description = "No entry for the given BPN was found"),
@ApiResponse(responseCode = "400", description = "Request body was malformed",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class))))
})
void updateEntry(JsonObject object);

@Operation(description = "Creates an entry for a particular BPN",
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = ListSchema.class))),

responses = {
@ApiResponse(responseCode = "204", description = "The object was successfully created"),
@ApiResponse(responseCode = "409", description = "An entry already exists for that BPN"),
@ApiResponse(responseCode = "400", description = "Request body was malformed",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class))))
})
void createEntry(JsonObject entry);


@Schema(name = "List", example = ListSchema.EXAMPLE)
record ListSchema(
@Schema(name = ID) String id,
Set<String> groups
) {
public static final String EXAMPLE = """
{
"@context": {
"tx": "https://w3id.org/tractusx/v0.0.1/ns/"
},
"@id": "tx:BPN000001234",
"tx:groups": ["group1", "group2", "group3"]
}
""";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft
*
* 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.edc.api.bpn;

import io.swagger.v3.oas.annotations.parameters.RequestBody;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonString;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.edc.web.spi.exception.InvalidRequestException;
import org.eclipse.edc.web.spi.exception.ObjectConflictException;
import org.eclipse.edc.web.spi.exception.ObjectNotFoundException;
import org.eclipse.tractusx.edc.validation.businesspartner.spi.BusinessPartnerStore;
import org.jetbrains.annotations.NotNull;

import java.util.List;

import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_NAMESPACE;


@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
@Path("/business-partner-groups")
public class BusinessPartnerGroupApiController implements BusinessPartnerGroupApi {

private final BusinessPartnerStore businessPartnerService;


public BusinessPartnerGroupApiController(BusinessPartnerStore businessPartnerService) {
this.businessPartnerService = businessPartnerService;
}

@GET
@Path("/{bpn}")
@Override
public JsonObject resolve(@PathParam("bpn") String bpn) {

// StoreResult does not support the .map() operator, because it does not override newInstance()
var result = businessPartnerService.resolveForBpn(bpn);
if (result.succeeded()) {
return createObject(bpn, result.getContent());
}

throw new ObjectNotFoundException(List.class, result.getFailureDetail());
}

@DELETE
@Path("/{bpn}")
@Override
public void deleteEntry(@PathParam("bpn") String bpn) {
businessPartnerService.delete(bpn)
.orElseThrow(f -> new ObjectNotFoundException(List.class, f.getFailureDetail()));
}

@PUT
@Override
public void updateEntry(@RequestBody JsonObject object) {
var bpn = getBpn(object);
var groups = getGroups(object);
businessPartnerService.update(bpn, groups)
.orElseThrow(f -> new ObjectNotFoundException(List.class, f.getFailureDetail()));
}

@POST
@Override
public void createEntry(@RequestBody JsonObject object) {
var bpn = getBpn(object);
var groups = getGroups(object);
businessPartnerService.save(bpn, groups)
.orElseThrow(f -> new ObjectConflictException(f.getFailureDetail()));
}

private JsonObject createObject(String bpn, List<String> list) {
return Json.createObjectBuilder()
.add(ID, bpn)
.add(TX_NAMESPACE + "groups", Json.createArrayBuilder(list))
.build();
}


private String getBpn(JsonObject object) {
try {
return object.getString(ID);
} catch (Exception ex) {
throw new InvalidRequestException(ex.getMessage());
}
}

@NotNull
private List<String> getGroups(JsonObject object) {
try {
return object.getJsonArray(TX_NAMESPACE + "groups").stream().map(jv -> ((JsonString) jv).getString()).toList();
} catch (Exception ex) {
throw new InvalidRequestException(ex.getMessage());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft
*
* 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.edc.api.bpn;

import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration;
import org.eclipse.edc.connector.api.management.configuration.transform.ManagementApiTypeTransformerRegistry;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.web.spi.WebService;
import org.eclipse.tractusx.edc.validation.businesspartner.spi.BusinessPartnerStore;

import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_NAMESPACE;
import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_PREFIX;

@Extension(value = "Registers the Business Partner Group API")
public class BusinessPartnerGroupApiExtension implements ServiceExtension {

@Inject
private WebService webService;
@Inject
private ManagementApiConfiguration apiConfiguration;
@Inject
private ManagementApiTypeTransformerRegistry transformerRegistry;
@Inject
private JsonLd jsonLdService;
@Inject
private BusinessPartnerStore businessPartnerStore;

@Override
public void initialize(ServiceExtensionContext context) {
jsonLdService.registerNamespace(TX_PREFIX, TX_NAMESPACE);

webService.registerResource(apiConfiguration.getContextAlias(), new BusinessPartnerGroupApiController(businessPartnerStore));

}
}
Loading

0 comments on commit 8670f2c

Please sign in to comment.