Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add API for the BPN validation extension #688

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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));

}
}