diff --git a/.gitignore b/.gitignore index 4320cfaa4..9cc77463c 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ _site/ # MacOS *.DS_Store +/http/restful-ws-jakarta/src/main/* + diff --git a/docs/http-jakarta-restful-ws-jakarta.md b/docs/http-jakarta-restful-ws-jakarta.md new file mode 100644 index 000000000..0eb4f43da --- /dev/null +++ b/docs/http-jakarta-restful-ws-jakarta.md @@ -0,0 +1,137 @@ +--- +title: CloudEvents HTTP Jakarta EE 9+ - Jakarta RESTful Web Services +nav_order: 5 +--- + +# HTTP Protocol Binding for Jakarta EE 9+ - Jakarta RESTful Web Services + +[![Javadocs](https://www.javadoc.io/badge/io.cloudevents/cloudevents-http-restful-ws.svg?color=green)](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws) + +For Maven based projects, use the following to configure the CloudEvents Jakarta +RESTful Web Services Binding for Jakarta EE 9+: + +```xml + + io.cloudevents + cloudevents-http-restful-ws-jakarta + 2.5.0-SNAPSHOT + +``` + +This integration is tested with Jersey (Requires JDK11 or higher), RestEasy & Microprofile Liberty. + +#### * Before using this package ensure your web framework does support the `jakarta.*` namespace. + +## Receiving CloudEvents + +You need to configure the `CloudEventsProvider` to enable +marshalling/unmarshalling of CloudEvents. + +Below is a sample on how to read and write CloudEvents: + +```java +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; + +@Path("/") +public class EventReceiverResource { + + + + @GET + @Path("getMinEvent") + public CloudEvent getMinEvent() { + return CloudEventBuilder.v1() + .withId("hello") + .withType("example.vertx") + .withSource(URI.create("http://localhost")) + .build(); + } + + // Return the CloudEvent using the HTTP binding structured encoding + @GET + @Path("getStructuredEvent") + @StructuredEncoding("application/cloudevents+csv") + public CloudEvent getStructuredEvent() { + return CloudEventBuilder.v1() + .withId("hello") + .withType("example.vertx") + .withSource(URI.create("http://localhost")) + .build(); + } + + @POST + @Path("postEventWithoutBody") + public Response postEvent(CloudEvent inputEvent) { + // Handle the event + return Response.ok().build(); + } +} +``` + +## Sending CloudEvents + +You need to configure the `CloudEventsProvider` to enable +marshalling/unmarshalling of CloudEvents. + +Below is a sample on how to use the client to send a CloudEvent: + +```java +import io.cloudevents.CloudEvent; +import io.cloudevents.http.restful.ws.CloudEventsProvider; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; + +public class CloudEventSender { + + public Response sendEvent(WebTarget target, CloudEvent event) { + return target + .path("postEvent") + .request() + .buildPost(Entity.entity(event, CloudEventsProvider.CLOUDEVENT_TYPE)) + .invoke(); + } + + public Response sendEventAsStructured(WebTarget target, CloudEvent event) { + return target + .path("postEvent") + .request() + .buildPost(Entity.entity(event, "application/cloudevents+json")) + .invoke(); + } + + public CloudEvent getEvent(WebTarget target) { + Response response = target + .path("getEvent") + .request() + .buildGet() + .invoke(); + + return response.readEntity(CloudEvent.class); + } +} +``` + +## Migrating EE 8 applications to EE 9+ +The main change between Jakarta EE 8 and Jakarta EE 9 and future versions is the changing of the `javax.` to `jakarta.` namespaces used by key packages such as `jakarta.ws.rs-api` which provides the restful-ws API. + +This change largely impacts only `import` statements it does filter down to dependencies such as this. + +### Application migration +For application migration we would recommend reviewing materials available from https://jakarta.ee/resources/#documentation as a starting point. + +### CloudEvents Dependency +To migrate to use EE 9+ supported package - replace `cloudevents-http-restful-ws` with `cloudevents-http-restful-ws-jakarta` and ensure the version is a minimum of `2.5.0-SNAPSHOT` + +## Examples + +- [Microprofile and Liberty](https://github.com/cloudevents/sdk-java/tree/master/examples/restful-ws-micropofile-liberty) + diff --git a/docs/http-jakarta-restful-ws.md b/docs/http-jakarta-restful-ws.md index a7f08fefb..6cc179944 100644 --- a/docs/http-jakarta-restful-ws.md +++ b/docs/http-jakarta-restful-ws.md @@ -3,12 +3,12 @@ title: CloudEvents HTTP Jakarta RESTful Web Services nav_order: 5 --- -# HTTP Protocol Binding for Jakarta RESTful Web Services +# HTTP Protocol Binding for Jakarta EE8 - RESTful Web Services [![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-http-restful-ws.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws) For Maven based projects, use the following to configure the CloudEvents Jakarta -RESTful Web Services Binding: +RESTful Web Services Binding for Jakarta EE 8: ```xml diff --git a/docs/index.md b/docs/index.md index ea4552f3a..07664c2ee 100644 --- a/docs/index.md +++ b/docs/index.md @@ -62,7 +62,8 @@ receive CloudEvents, check out the dedicated pages: - [AMQP using Proton](amqp-proton.md) - [HTTP using Vert.x](http-vertx.md) -- [HTTP using Jakarta Restful WS](http-jakarta-restful-ws.md) +- [HTTP using Jakarta EE 8 - Jakarta Restful WS](http-jakarta-restful-ws.md) +- [HTTP using Jakarta EE 9+ - Jakarta Restful WS](http-jakarta-restful-ws-jakarta.md) - [HTTP using Spring](spring.md) - [HTTP using Jackson](json-jackson.md) - [Kafka](kafka.md) @@ -98,7 +99,9 @@ a different feature from the different sub specs of - [`cloudevents-http-vertx`] Implementation of [HTTP Protocol Binding] with [Vert.x Core](https://vertx.io/) - [`cloudevents-http-restful-ws`] Implementation of [HTTP Protocol Binding] - for [Jakarta Restful WS](https://jakarta.ee/specifications/restful-ws/) + for [Jakarta EE 8 Restful WS](https://jakarta.ee/specifications/restful-ws/2.1/) +- [`cloudevents-http-restful-ws-jakarta`] Implementation of [HTTP Protocol Binding] + for [Jakarta EE 9+ Restful WS](https://jakarta.ee/specifications/restful-ws/) - [`cloudevents-http-basic`] Generic implementation of [HTTP Protocol Binding], primarily intended for integrators - [`cloudevents-kafka`] Implementation of [Kafka Protocol Binding] @@ -123,6 +126,7 @@ You can look at the latest published artifacts on [`cloudevents-http-vertx`]: https://github.com/cloudevents/sdk-java/tree/master/http/vertx [`cloudevents-http-basic`]: https://github.com/cloudevents/sdk-java/tree/master/http/basic [`cloudevents-http-restful-ws`]: https://github.com/cloudevents/sdk-java/tree/master/http/restful-ws +[`cloudevents-http-restful-ws-jakarta`]: https://github.com/cloudevents/sdk-java/tree/master/http/restful-ws-jakarta [`cloudevents-kafka`]: https://github.com/cloudevents/sdk-java/tree/master/kafka [`cloudevents-amqp-proton`]: https://github.com/cloudevents/sdk-java/tree/master/amqp [`cloudevents-spring`]: https://github.com/cloudevents/sdk-java/tree/master/spring diff --git a/examples/pom.xml b/examples/pom.xml index 4f384d36a..a706a51e2 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,6 +21,7 @@ kafka restful-ws-quarkus + restful-ws-microprofile-liberty vertx basic-http restful-ws-spring-boot diff --git a/examples/restful-ws-microprofile-liberty/README.md b/examples/restful-ws-microprofile-liberty/README.md new file mode 100644 index 000000000..a5a320222 --- /dev/null +++ b/examples/restful-ws-microprofile-liberty/README.md @@ -0,0 +1,140 @@ +# Cloudevents Restful WS Microprofile Example + +This project uses Microprofile 5.0 with OpenLiberty + +If you would like to know more about Microprofile go to https://microprofile.io + +This Example uses Jakarta EE9 features as such the top level namespace of the `ws-api` packages has changed from `javax` to `jakarta` and uses the `cloudevents-http-restful-ws-jakarta` artifact. + +## Build and Execution + +### Running the application in dev mode + +You can run your application in dev mode that enables live coding using: +``` +mvn liberty:dev +``` + +### Packaging and running the application + +To Package and run as a minimum jar without a full OpenLiberty server +``` +mvn liberty:package -Drunnable=mvn liberty:package -Dinclude=runnable +``` + +### Making requests against the server + +This sample application has a `/events` RESTful endpoint on the application `cloudevents-restful-ws-microprofile-example +the base application is available at `http://localhost:9080/cloudevents-restful-ws-microprofile-example/` + +There are three operations that can be performed: +#### GET /events +Returns a Cloud event with a payload containing a message + +```shell +curl -v http://localhost:9080/cloudevents-restful-ws-microprofile-example/events + +* Trying 127.0.0.1:9080... +* Connected to localhost (127.0.0.1) port 9080 (#0) +> GET /cloudevents-restful-ws-microprofile-example/events HTTP/1.1 +> Host: localhost:9080 +> User-Agent: curl/7.83.1 +> Accept: */* +> +* Mark bundle as not supporting multiuse +< HTTP/1.1 201 no-content +< Ce-Id: hello +< Ce-Source: http://localhost +< Ce-Specversion: 1.0 +< Ce-Type: example.http +< Content-Type: application/json +< Content-Language: en-GB +< Content-Length: 64 +< Date: Wed, 17 Aug 2022 14:01:50 GMT +< +{"message":"Welcome to this Cloudevents + Microprofile example"} +``` + +#### POST /events +POST a Cloudevent with a payload that is printed out in the server logs + +```shell +curl -v http://localhost:9080/cloudevents-restful-ws-microprofile-example/events \ +-H "Ce-Specversion: 1.0" \ +-H "Ce-Type: User" \ +-H "Ce-Source: io.cloudevents.examples/user" \ +-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f78" \ +-H "Content-Type: application/json" \ +-H "Ce-Subject: SUBJ-0001" \ +-d "hello" + +* Trying 127.0.0.1:9080... +* Connected to localhost (127.0.0.1) port 9080 (#0) +> POST /cloudevents-restful-ws-microprofile-example/events HTTP/1.1 +> Host: localhost:9080 +> User-Agent: curl/7.83.1 +> Accept: */* +> Ce-Specversion: 1.0 +> Ce-Type: User +> Ce-Source: io.cloudevents.examples/user +> Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f78 +> Content-Type: application/json +> Ce-Subject: SUBJ-0001 +> Content-Length: 5 +> +* Mark bundle as not supporting multiuse +< HTTP/1.1 204 No Content +< Content-Language: en-GB +< Content-Length: 0 +< Date: Thu, 18 Aug 2022 13:33:03 GMT +< +* Connection #0 to host localhost left intact +``` +Server log statement +``` +[INFO] Received request providing a event with body hello +[INFO] CloudEvent{id='536808d3-88be-4077-9d7a-a3f162705f78', source=io.cloudevents.examples/user, type='User', datacontenttype='application/json', subject='SUBJ-0001', data=BytesCloudEventData{value=[104, 101, 108, 108, 111]}, extensions={}} +``` + +#### POST /events/echo +POST a Cloudevent with a payload and have it echoed back as a Cloudevent + +```shell +curl -v http://localhost:9080/cloudevents-restful-ws-microprofile-example/events/echo \ +-H "Ce-Specversion: 1.0" \ +-H "Ce-Type: User" \ +-H "Ce-Source: io.cloudevents.examples/user" \ +-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f78" \ +-H "Content-Type: application/json" \ +-H "Ce-Subject: SUBJ-0001" \ +-d "hello" + +* Trying 127.0.0.1:9080... +* Connected to localhost (127.0.0.1) port 9080 (#0) +> POST /cloudevents-restful-ws-microprofile-example/rest/events/echo HTTP/1.1 +> Host: localhost:9080 +> User-Agent: curl/7.83.1 +> Accept: */* +> Ce-Specversion: 1.0 +> Ce-Type: User +> Ce-Source: io.cloudevents.examples/user +> Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f78 +> Content-Type: application/json +> Ce-Subject: SUBJ-0001 +> Content-Length: 5 +> +* Mark bundle as not supporting multiuse +< HTTP/1.1 200 OK +< Ce-Id: echo +< Ce-Source: http://localhost +< Ce-Specversion: 1.0 +< Ce-Type: echo.http +< Content-Type: application/json +< Content-Language: en-GB +< Content-Length: 17 +< Date: Wed, 17 Aug 2022 12:57:59 GMT +< +{"echo": "hello"}* Connection #0 to host localhost left intact +``` + + diff --git a/examples/restful-ws-microprofile-liberty/pom.xml b/examples/restful-ws-microprofile-liberty/pom.xml new file mode 100644 index 000000000..fa62353c0 --- /dev/null +++ b/examples/restful-ws-microprofile-liberty/pom.xml @@ -0,0 +1,184 @@ + + + cloudevents-examples + io.cloudevents + 2.5.0-SNAPSHOT + ../ + + 4.0.0 + cloudevents-restful-ws-microprofile-liberty-example + war + + + 3.5.1 + cloudevents-microprofile + + + cloudeventsServer + 9080 + 9443 + + cloudeventsexperiments + ${project.build.directory}/${app.name}.zip + UTF-8 + + + + + runnable + + ${project.build.directory}/${app.name}.jar + runnable + + + + + + + org.eclipse.microprofile + microprofile + 5.0 + pom + provided + + + io.cloudevents + cloudevents-http-restful-ws-jakarta + ${project.parent.version} + + + io.projectreactor + reactor-core + 3.4.21 + + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.2 + + false + pom.xml + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + copy-server-files + package + + copy-dependencies + + + server-snippet + true + + ${project.build.directory}/wlp/usr/servers/${wlpServerName}/configDropins/defaults + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + + copy-app + package + + copy-resources + + + ${project.build.directory}/wlp/usr/servers/${wlpServerName}/dropins + + + + ${project.build.directory} + + ${project.artifactId}-${project.version}.war + + + + + + + + + + io.openliberty.tools + liberty-maven-plugin + ${openliberty.maven.version} + + + package-server + package + + create + install-feature + deploy + package + + + target/wlp-package + + + + + runnable + ${final.name} + + ${final.name} + https://server.example.com + / + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.18.1 + + + integration-test + integration-test + + integration-test + + + + **/it/** + + + ${testServerHttpPort} + ${warContext} + ${running.bluemix} + ${cf.context.root} + + + + + verify-results + + verify + + + + + ${project.build.directory}/test-reports/it/failsafe-summary.xml + ${project.build.directory}/test-reports/it + + + + + diff --git a/examples/restful-ws-microprofile-liberty/src/main/java/io/cloudevents/examples/microprofile/CloudEventsApplication.java b/examples/restful-ws-microprofile-liberty/src/main/java/io/cloudevents/examples/microprofile/CloudEventsApplication.java new file mode 100644 index 000000000..fc212316f --- /dev/null +++ b/examples/restful-ws-microprofile-liberty/src/main/java/io/cloudevents/examples/microprofile/CloudEventsApplication.java @@ -0,0 +1,9 @@ +package io.cloudevents.examples.microprofile; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("/") +public class CloudEventsApplication extends Application { + +} diff --git a/examples/restful-ws-microprofile-liberty/src/main/java/io/cloudevents/examples/microprofile/CloudEventsJaxrsService.java b/examples/restful-ws-microprofile-liberty/src/main/java/io/cloudevents/examples/microprofile/CloudEventsJaxrsService.java new file mode 100644 index 000000000..eef7fe882 --- /dev/null +++ b/examples/restful-ws-microprofile-liberty/src/main/java/io/cloudevents/examples/microprofile/CloudEventsJaxrsService.java @@ -0,0 +1,56 @@ +package io.cloudevents.examples.microprofile; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import jakarta.enterprise.context.RequestScoped; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +import java.net.URI; +import java.nio.charset.StandardCharsets; + +@RequestScoped +@Path("events") +public class CloudEventsJaxrsService { + + + @GET + @Produces(MediaType.APPLICATION_JSON) + public CloudEvent retrieveEvent(){ + System.out.println("Received request for an event"); + return CloudEventBuilder.v1() + .withData("{\"message\":\"Welcome to this Cloudevents + Microprofile example\"}".getBytes()) + .withDataContentType("application/json") + .withId("hello") + .withType("example.http") + .withSource(URI.create("http://localhost")) + .build(); + } + + //Example Curl - curl -v http://localhost:9080/cloudevents-restful-ws-microprofile-example/events -H "Ce-Specversion: 1.0" -H "Ce-Type: User" -H "Ce-Source: io.cloudevents.examples/user" -H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f78" -H "Content-Type: application/json" -H "Ce-Subject: SUBJ-0001" -d "hello" + + @POST + @Consumes(MediaType.APPLICATION_JSON) + public Response postEvent(CloudEvent event){ + System.out.println("Received request providing a event with body "+ new String(event.getData().toBytes(), StandardCharsets.UTF_8)); + System.out.println(event); + return Response.noContent().build(); + } + + //Example Curl - curl -v http://localhost:9080/cloudevents-restful-ws-microprofile-example/events/echo -H "Ce-Specversion: 1.0" -H "Ce-Type: User" -H "Ce-Source: io.cloudevents.examples/user" -H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f78" -H "Content-Type: application/json" -H "Ce-Subject: SUBJ-0001" -d "hello" + + @POST + @Path("/echo") + @Consumes(MediaType.APPLICATION_JSON) + public CloudEvent echo(CloudEvent event){ + return CloudEventBuilder.v1() + .withData("application/json", ("{\"echo\": \"" + new String(event.getData().toBytes(),StandardCharsets.UTF_8) + "\"}").getBytes()) + .withId("echo") + .withType("echo.http") + .withSource(URI.create("http://localhost")) + .build(); + } + + +} diff --git a/examples/restful-ws-microprofile-liberty/src/main/liberty/config/server.xml b/examples/restful-ws-microprofile-liberty/src/main/liberty/config/server.xml new file mode 100644 index 000000000..eaac3901f --- /dev/null +++ b/examples/restful-ws-microprofile-liberty/src/main/liberty/config/server.xml @@ -0,0 +1,25 @@ + + + + + microProfile-5.0 + + + + + + + + + + + + + + + + + + diff --git a/http/restful-ws-jakarta-integration-tests/pom.xml b/http/restful-ws-jakarta-integration-tests/pom.xml new file mode 100644 index 000000000..11e49266c --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/pom.xml @@ -0,0 +1,30 @@ + + + + cloudevents-parent + io.cloudevents + 2.5.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + + cloudevents-http-restful-ws-jakarta-integration-tests + CloudEvents - JAX-RS Jakarta EE9+ Web Http Binding Integration Tests + pom + + + + true + + + + restful-ws-jakarta-common + restful-ws-resteasy + + + restful-ws-liberty + + + diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/pom.xml new file mode 100644 index 000000000..d9d63d571 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/pom.xml @@ -0,0 +1,38 @@ + + + cloudevents-http-restful-ws-jakarta-integration-tests + io.cloudevents + 2.5.0-SNAPSHOT + ../ + + 4.0.0 + cloudevents-http-restful-ws-jakarta-integration-tests-common + CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - Common + jar + + + + io.cloudevents + cloudevents-http-restful-ws-jakarta + ${project.version} + + + io.cloudevents + cloudevents-core + tests + test-jar + ${project.version} + + + org.assertj + assertj-core + ${assertj-core.version} + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + + + diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java new file mode 100644 index 000000000..ea5cc7569 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/BaseTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2018-Present The CloudEvents Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://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. + * + */ + +package io.cloudevents.http.restful.ws; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.mock.CSVFormat; +import io.cloudevents.core.test.Data; +import org.junit.jupiter.api.Test; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; + +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class BaseTest { + + protected abstract WebTarget getWebTarget(); + + @Test + void getMinEvent() { + Response res = getWebTarget().path("getMinEvent").request().buildGet().invoke(); + + assertThat(res.getHeaderString("ce-specversion")) + .isEqualTo("1.0"); + + CloudEvent outEvent = res.readEntity(CloudEvent.class); + assertThat(outEvent) + .isEqualTo(Data.V1_MIN); + } + + @Test + void getStructuredEvent() { + Response res = getWebTarget().path("getStructuredEvent").request().buildGet().invoke(); + + CloudEvent outEvent = res.readEntity(CloudEvent.class); + assertThat(outEvent) + .isEqualTo(Data.V1_MIN); + assertThat(res.getHeaderString(HttpHeaders.CONTENT_TYPE)) + .isEqualTo(CSVFormat.INSTANCE.serializedContentType()); + } + + @Test + void getEvent() { + Response res = getWebTarget().path("getEvent").request().buildGet().invoke(); + + CloudEvent outEvent = res.readEntity(CloudEvent.class); + assertThat(outEvent) + .isEqualTo(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING); + } + + @Test + void postEventWithoutBody() { + Response res = getWebTarget() + .path("postEventWithoutBody") + .request() + .buildPost(Entity.entity(Data.V1_MIN, CloudEventsProvider.CLOUDEVENT_TYPE)) + .invoke(); + + assertThat(res.getStatus()) + .isEqualTo(200); + } + + @Test + void postEventStructured() { + Response res = getWebTarget() + .path("postEventWithoutBody") + .request() + .buildPost(Entity.entity(Data.V1_MIN, "application/cloudevents+csv")) + .invoke(); + + assertThat(res.getStatus()) + .isEqualTo(200); + } + + @Test + void postEvent() { + Response res = getWebTarget() + .path("postEvent") + .request() + .buildPost(Entity.entity(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, CloudEventsProvider.CLOUDEVENT_TYPE)) + .invoke(); + + assertThat(res.getStatus()) + .isEqualTo(200); + } +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java new file mode 100644 index 000000000..923a8572d --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-jakarta-common/src/main/java/io/cloudevents/http/restful/ws/TestResource.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018-Present The CloudEvents Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://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. + * + */ + +package io.cloudevents.http.restful.ws; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.test.Data; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; + +@Path("/") +public class TestResource { + + @GET + @Path("getMinEvent") + public CloudEvent getMinEvent() { + return Data.V1_MIN; + } + + @GET + @Path("getStructuredEvent") + @StructuredEncoding("application/cloudevents+csv") + public CloudEvent getStructuredEvent() { + return Data.V1_MIN; + } + + @GET + @Path("getEvent") + public CloudEvent getEvent() { + return Data.V1_WITH_JSON_DATA_WITH_EXT_STRING; + } + + @POST + @Path("postEventWithoutBody") + public Response postEventWithoutBody(CloudEvent inputEvent) { + if (inputEvent.equals(Data.V1_MIN)) { + return Response.ok().build(); + } + return Response.serverError().build(); + } + + @POST + @Path("postEvent") + public Response postEvent(CloudEvent inputEvent) { + if (inputEvent.equals(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING)) { + return Response.ok().build(); + } + return Response.serverError().build(); + } +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/pom.xml new file mode 100644 index 000000000..fdf8bd9f5 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/pom.xml @@ -0,0 +1,73 @@ + + + + + + cloudevents-http-restful-ws-jakarta-integration-tests + io.cloudevents + 2.5.0-SNAPSHOT + ../ + + 4.0.0 + + cloudevents-http-restful-ws-jakarta-integration-tests-jersey + CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - Jersey + jar + + + 3.0.8 + 3.0.0 + + + + + + io.cloudevents + cloudevents-http-restful-ws-jakarta-integration-tests-common + ${project.version} + test + + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta-ee.version} + test + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-jetty + ${jersey.version} + test + + + org.glassfish.jersey.inject + jersey-hk2 + ${jersey.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/com/github/hanleyt/JerseyExtension.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/com/github/hanleyt/JerseyExtension.java new file mode 100644 index 000000000..066535c05 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/com/github/hanleyt/JerseyExtension.java @@ -0,0 +1,130 @@ +/* + * Ported from https://github.com/hanleyt/jersey-junit as no version supports Jesery versions >=3.0.0 + * + * Only update is the replacement of the ws-rs package namespace from javax. to jakarta. + */ + +package com.github.hanleyt; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.TestProperties; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolver; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import java.net.URI; +import java.util.Arrays; +import java.util.Collection; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +public class JerseyExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { + + private static final Collection> INJECTABLE_PARAMETER_TYPES = Arrays.asList(Client.class, WebTarget.class, URI.class); + + private final Function testContainerFactoryProvider; + private final Function deploymentContextProvider; + private final BiFunction configProvider; + + private JerseyExtension() { + throw new IllegalStateException("JerseyExtension must be registered programmatically"); + } + + public JerseyExtension(Supplier applicationSupplier) { + this((unused) -> applicationSupplier.get(), null); + } + + public JerseyExtension(Supplier applicationSupplier, + BiFunction configProvider) { + this((unused) -> applicationSupplier.get(), configProvider); + } + + public JerseyExtension(Function applicationProvider) { + this(applicationProvider, null); + } + + public JerseyExtension(Function applicationProvider, + BiFunction configProvider) { + this(null, (context) -> DeploymentContext.builder(applicationProvider.apply(context)).build(), configProvider); + } + + public JerseyExtension(Function testContainerFactoryProvider, + Function deploymentContextProvider, + BiFunction configProvider) { + this.testContainerFactoryProvider = testContainerFactoryProvider; + this.deploymentContextProvider = deploymentContextProvider; + this.configProvider = configProvider; + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + JerseyTest jerseyTest = initJerseyTest(context); + getStore(context).put(Client.class, jerseyTest.client()); + getStore(context).put(WebTarget.class, jerseyTest.target()); + getStore(context).put(URI.class, jerseyTest.target().getUri()); + } + + private JerseyTest initJerseyTest(ExtensionContext context) throws Exception { + JerseyTest jerseyTest = new JerseyTest() { + + @Override + protected DeploymentContext configureDeployment() { + forceSet(TestProperties.CONTAINER_PORT, "0"); + return deploymentContextProvider.apply(context); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + if (testContainerFactoryProvider != null) { + return testContainerFactoryProvider.apply(context); + } + return super.getTestContainerFactory(); + } + + @Override + protected void configureClient(ClientConfig config) { + if (configProvider != null) { + config = configProvider.apply(context, config); + } + super.configureClient(config); + } + }; + jerseyTest.setUp(); + getStore(context).put(JerseyTest.class, jerseyTest); + return jerseyTest; + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + ExtensionContext.Store store = getStore(context); + store.remove(JerseyTest.class, JerseyTest.class).tearDown(); + INJECTABLE_PARAMETER_TYPES.forEach(store::remove); + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + Class parameterType = parameterContext.getParameter().getType(); + return INJECTABLE_PARAMETER_TYPES.contains(parameterType); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + Class parameterType = parameterContext.getParameter().getType(); + return getStore(extensionContext).get(parameterType, parameterType); + } + + public static ExtensionContext.Store getStore(ExtensionContext context) { + return context.getStore(ExtensionContext.Namespace.GLOBAL); + } + +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jakarta/jersey/TestJersey.java b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jakarta/jersey/TestJersey.java new file mode 100644 index 000000000..fb54c3164 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-jersey/src/test/java/io/cloudevents/http/restful/ws/jakarta/jersey/TestJersey.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018-Present The CloudEvents Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://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. + * + */ + +package io.cloudevents.http.restful.ws.jakarta.jersey; + +import com.github.hanleyt.JerseyExtension; +import io.cloudevents.core.mock.CSVFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.http.restful.ws.BaseTest; +import io.cloudevents.http.restful.ws.CloudEventsProvider; +import io.cloudevents.http.restful.ws.TestResource; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.RegisterExtension; + +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; + +public class TestJersey extends BaseTest { + + private WebTarget target; + + @Override + protected WebTarget getWebTarget() { + return target; + } + + @BeforeAll + public static void beforeAll() { + EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); + } + + @BeforeEach + void beforeEach(WebTarget target) { + this.target = target; + } + + @RegisterExtension + JerseyExtension jerseyExtension = new JerseyExtension(this::configureJersey, this::configureJerseyClient); + + private Application configureJersey() { + return new ResourceConfig(TestResource.class) + .register(CloudEventsProvider.class); + } + + private ClientConfig configureJerseyClient(ExtensionContext extensionContext, ClientConfig clientConfig) { + return clientConfig + .register(CloudEventsProvider.class); + } + +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/pom.xml new file mode 100644 index 000000000..1789438fb --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/pom.xml @@ -0,0 +1,161 @@ + + + + cloudevents-http-restful-ws-jakarta-integration-tests + io.cloudevents + 2.5.0-SNAPSHOT + ../ + + 4.0.0 + + cloudevents-http-restful-ws-jakarta-integration-tests-microprofile + CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - Microprofile and Liberty + war + + + + 9080 + 9443 + + microprofile-test + + + + + + org.jboss.arquillian + arquillian-bom + 1.6.0.Final + pom + import + + + + + + + + jakarta.platform + jakarta.jakartaee-api + 9.1.0 + provided + + + org.eclipse.microprofile + microprofile + 5.0 + pom + provided + + + io.cloudevents + cloudevents-http-restful-ws-jakarta + ${project.version} + + + io.cloudevents + cloudevents-core + tests + test-jar + ${project.version} + + + org.jboss.resteasy + resteasy-client + 6.0.3.Final + test + + + org.jboss.resteasy + resteasy-json-binding-provider + 6.0.3.Final + test + + + org.glassfish + jakarta.json + 2.0.1 + test + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + javax.activation + activation + 1.1.1 + + + io.openliberty.arquillian + arquillian-liberty-managed-jakarta-junit + 2.1.0 + pom + test + + + org.jboss.shrinkwrap + shrinkwrap-api + test + + + + + ${project.artifactId} + + + org.apache.maven.plugins + maven-war-plugin + 3.3.2 + + pom.xml + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.22.2 + + + ${arquillian.war.name}.war + + + + + test + + integration-test + + + + + + io.openliberty.tools + liberty-maven-plugin + 3.5.1 + + + + -Dsystem.context.root=/${arquillian.war.name} + + + + + + arquillian-configuration + generate-test-resources + + create + install-feature + configure-arquillian + + + + + + + diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/MpCEApp.java b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/MpCEApp.java new file mode 100644 index 000000000..279cdb3e4 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/MpCEApp.java @@ -0,0 +1,9 @@ +package io.cloudevents.restful.mp.test; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("/") +public class MpCEApp extends Application { + +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/TestResource.java b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/TestResource.java new file mode 100644 index 000000000..5a73efeb6 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/java/io/cloudevents/restful/mp/test/TestResource.java @@ -0,0 +1,60 @@ +package io.cloudevents.restful.mp.test; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.mock.CSVFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.core.test.Data; +import io.cloudevents.http.restful.ws.StructuredEncoding; +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.RequestScoped; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; + +@RequestScoped +@Path("/") +public class TestResource{ + + @PostConstruct + void init() { + EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); + } + + @GET + @Path("getMinEvent") + public CloudEvent getMinEvent() { + return Data.V1_MIN; + } + + @GET + @Path("getStructuredEvent") + @StructuredEncoding("application/cloudevents+csv") + public CloudEvent getStructuredEvent() { + return Data.V1_MIN; + } + + @GET + @Path("getEvent") + public CloudEvent getEvent() { + return Data.V1_WITH_JSON_DATA_WITH_EXT_STRING; + } + + @POST + @Path("postEventWithoutBody") + public Response postEventWithoutBody(CloudEvent inputEvent) { + if (inputEvent.equals(Data.V1_MIN)) { + return Response.ok().build(); + } + return Response.serverError().build(); + } + + @POST + @Path("postEvent") + public Response postEvent(CloudEvent inputEvent) { + if (inputEvent.equals(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING)) { + return Response.ok().build(); + } + return Response.serverError().build(); + } +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/liberty/config/server.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/liberty/config/server.xml new file mode 100644 index 000000000..9725cb9c8 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/main/liberty/config/server.xml @@ -0,0 +1,18 @@ + + + + microProfile-5.0 + + localConnector-1.0 + servlet-5.0 + + + + + + + + + + diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/test/java/io/cloudevents/http/restful/ws/jakarta/microprofile/TestMicroprofile.java b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/test/java/io/cloudevents/http/restful/ws/jakarta/microprofile/TestMicroprofile.java new file mode 100644 index 000000000..184fa2c8d --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-liberty/src/test/java/io/cloudevents/http/restful/ws/jakarta/microprofile/TestMicroprofile.java @@ -0,0 +1,123 @@ +package io.cloudevents.http.restful.ws.jakarta.microprofile; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.mock.CSVFormat; +import io.cloudevents.core.test.Data; +import io.cloudevents.http.restful.ws.CloudEventsProvider; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.URL; + + +/** + * Arquilian does not support assertj, so test cases have been ported to Junit to work with arquilian + */ +@RunWith(Arquillian.class) +public class TestMicroprofile { + + private static final String WARNAME = "microprofile-test.war"; + private Client client = ClientBuilder.newClient(); + + @Deployment(testable = true) + public static WebArchive createDeployment() { + System.out.println(WARNAME); + WebArchive archive = ShrinkWrap.create(WebArchive.class, WARNAME).addPackages(true,"io.cloudevents"); + return archive; + } + + @ArquillianResource + private URL baseURL; + + private WebTarget webTarget; + + public WebTarget getWebTarget() { + if(webTarget == null){ + webTarget = client.target(baseURL.toString()); + webTarget.register(CloudEventsProvider.class); + } + return webTarget; + } + + @Test + @RunAsClient + public void getMinEvent() { + Response res = getWebTarget().path("getMinEvent").request().buildGet().invoke(); + + Assert.assertEquals("1.0",res.getHeaderString("ce-specversion")); + Assert.assertEquals(Data.V1_MIN,res.readEntity(CloudEvent.class)); + + res.close(); + } + + @Test + @RunAsClient + public void getStructuredEvent() { + Response res = getWebTarget().path("getStructuredEvent").request().buildGet().invoke(); + + Assert.assertEquals(Data.V1_MIN,res.readEntity(CloudEvent.class)); + Assert.assertEquals(CSVFormat.INSTANCE.serializedContentType(),res.getHeaderString(HttpHeaders.CONTENT_TYPE)); + + res.close(); + } + + @Test + @RunAsClient + public void testGetEvent() throws Exception { + Response response = getWebTarget().path("getEvent").request().buildGet().invoke(); + + Assert.assertEquals("Valid response code", 200, response.getStatus()); + Assert.assertEquals("should match", Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, response.readEntity(CloudEvent.class)); + + response.close(); + } + + @Test + @RunAsClient + public void postEventWithoutBody() { + Response res = getWebTarget() + .path("postEventWithoutBody") + .request() + .buildPost(Entity.entity(Data.V1_MIN, CloudEventsProvider.CLOUDEVENT_TYPE)) + .invoke(); + + Assert.assertEquals(200,res.getStatus()); + } + + @Test + @RunAsClient + public void postEventStructured() { + Response res = getWebTarget() + .path("postEventWithoutBody") + .request() + .buildPost(Entity.entity(Data.V1_MIN, "application/cloudevents+csv")) + .invoke(); + + Assert.assertEquals(200,res.getStatus()); + } + + @Test + @RunAsClient + public void postEvent() { + Response res = getWebTarget() + .path("postEvent") + .request() + .buildPost(Entity.entity(Data.V1_WITH_JSON_DATA_WITH_EXT_STRING, CloudEventsProvider.CLOUDEVENT_TYPE)) + .invoke(); + + Assert.assertEquals(200,res.getStatus()); + } +} diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/pom.xml b/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/pom.xml new file mode 100644 index 000000000..08a87fa73 --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/pom.xml @@ -0,0 +1,45 @@ + + + cloudevents-http-restful-ws-jakarta-integration-tests + io.cloudevents + 2.5.0-SNAPSHOT + ../ + + 4.0.0 + + cloudevents-http-restful-ws-jakarta-integration-tests-resteasy + CloudEvents - JAX-RS Jakarta EE9+ Integration Tests - RESTEasy + jar + + + + 4.3.3 + 6.0.3.Final + + + + + + io.cloudevents + cloudevents-http-restful-ws-jakarta-integration-tests-common + ${project.version} + test + + + + io.vertx + vertx-core + ${vertx.version} + test + + + org.jboss.resteasy + resteasy-vertx + ${resteasy.version} + test + + + + + diff --git a/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/jakarta/resteasy/TestResteasy.java b/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/jakarta/resteasy/TestResteasy.java new file mode 100644 index 000000000..5cac8fdff --- /dev/null +++ b/http/restful-ws-jakarta-integration-tests/restful-ws-resteasy/src/test/java/io/cloudevents/http/restful/ws/jakarta/resteasy/TestResteasy.java @@ -0,0 +1,62 @@ + +/* + * Copyright 2018-Present The CloudEvents Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://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. + * + */ + +package io.cloudevents.http.restful.ws.jakarta.resteasy; + +import io.cloudevents.core.mock.CSVFormat; +import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.http.restful.ws.BaseTest; +import io.cloudevents.http.restful.ws.CloudEventsProvider; +import io.cloudevents.http.restful.ws.TestResource; +import org.jboss.resteasy.plugins.server.vertx.VertxContainer; +import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment; +import org.jboss.resteasy.test.TestPortProvider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; + +public class TestResteasy extends BaseTest { + + private static VertxResteasyDeployment resteasyDeployment; + private static WebTarget target; + + @Override + protected WebTarget getWebTarget() { + return target; + } + + @BeforeAll + public static void beforeClass() throws Exception { + EventFormatProvider.getInstance().registerFormat(CSVFormat.INSTANCE); + + String base = TestPortProvider.generateBaseUrl(); + TestResteasy.resteasyDeployment = VertxContainer.start(base); + TestResteasy.resteasyDeployment.getProviderFactory().register(CloudEventsProvider.class); + TestResteasy.resteasyDeployment.getRegistry().addPerRequestResource(TestResource.class); + + TestResteasy.target = ClientBuilder.newClient().register(CloudEventsProvider.class).target(base); + } + + @AfterAll + public static void after() throws Exception { + TestResteasy.resteasyDeployment.stop(); + } + +} diff --git a/http/restful-ws-jakarta/README.md b/http/restful-ws-jakarta/README.md new file mode 100644 index 000000000..8f676ce2e --- /dev/null +++ b/http/restful-ws-jakarta/README.md @@ -0,0 +1,7 @@ +# HTTP Protocol Binding for Jakarta EE9+ - Jakarta RESTful Web Services + +Javadocs: [![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-http-restful-ws.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws) + +Documentation: https://cloudevents.github.io/sdk-java/http-jakarta-restful-ws + +The code for this package lies within the [restful-ws](https://github.com/cloudevents/sdk-java/tree/master/http/restful-ws) directory and is copied within here and has `javax.` replaced with `jakarta.` diff --git a/http/restful-ws-jakarta/pom.xml b/http/restful-ws-jakarta/pom.xml new file mode 100644 index 000000000..6d64b836c --- /dev/null +++ b/http/restful-ws-jakarta/pom.xml @@ -0,0 +1,97 @@ + + + + 4.0.0 + + io.cloudevents + cloudevents-parent + 2.5.0-SNAPSHOT + ../../pom.xml + + + cloudevents-http-restful-ws-jakarta + CloudEvents - Jakarta EE 9+ - Jakarta RESTful Web Services Http Binding + jar + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + default + + true + + + + + + 3.0.0 + 3.0.8 + 4.4.3 + 6.0.3.Final + io.cloudevents.http.restfulws + + + + + io.cloudevents + cloudevents-core + ${project.version} + + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta-ee.version} + + + + + + + maven-antrun-plugin + 3.0.0 + + + generate-sources + + + + + + + + + + + + + + + + + + run + + + + + + + + diff --git a/pom.xml b/pom.xml index 1071d3792..c959a6441 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ http/basic http/vertx http/restful-ws + http/restful-ws-jakarta kafka spring sql @@ -209,6 +210,7 @@ benchmarks http/restful-ws-integration-tests + http/restful-ws-jakarta-integration-tests examples