Compare commits

...

143 Commits

Author SHA1 Message Date
Pierangelo Di Pilato 0d96691f6d
Migrate from OSSRH to Central Portal (#698)
Ref: https://central.sonatype.org/publish/publish-portal-maven/

Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2025-06-26 09:44:36 +02:00
Sleiman Jneidi c8a22b5175
build: upgrage to protobuf sdk 4.31.1 (#695)
Signed-off-by: Sleiman <sleiman.jneidi@apple.com>
Co-authored-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2025-06-20 14:56:34 +02:00
Sleiman Jneidi 57f9867a5c
build: remove maven cache (#696)
Signed-off-by: Sleiman <sleiman.jneidi@apple.com>
2025-06-20 09:43:41 +02:00
dependabot[bot] 43f0d5b138
Bump nokogiri from 1.16.5 to 1.18.3 in /docs (#685)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.16.5 to 1.18.3.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/v1.18.3/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.16.5...v1.18.3)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 08:18:56 +01:00
dependabot[bot] efe7e01b75
Bump org.apache.maven.plugins:maven-antrun-plugin from 3.0.0 to 3.1.0 (#682)
Bumps [org.apache.maven.plugins:maven-antrun-plugin](https://github.com/apache/maven-antrun-plugin) from 3.0.0 to 3.1.0.
- [Commits](https://github.com/apache/maven-antrun-plugin/compare/maven-antrun-plugin-3.0.0...maven-antrun-plugin-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-antrun-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-27 10:03:16 +01:00
dependabot[bot] 188c3c7085
Bump org.apache.qpid:proton-j from 0.33.7 to 0.34.1 (#678)
Bumps org.apache.qpid:proton-j from 0.33.7 to 0.34.1.

---
updated-dependencies:
- dependency-name: org.apache.qpid:proton-j
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-20 13:13:12 +01:00
dependabot[bot] 659bb8cc01
Bump org.apache.kafka:kafka-clients from 3.0.0 to 3.7.1 in /kafka (#681)
Bumps org.apache.kafka:kafka-clients from 3.0.0 to 3.7.1.

---
updated-dependencies:
- dependency-name: org.apache.kafka:kafka-clients
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-20 13:12:46 +01:00
Kristiyan Marinov 9981635e7d
fix: disallow empty 'subject' context attribute (#679)
Specification clearly states that 'subject' is optional but if present, MUST be non-empty
(spec at https://github.com/cloudevents/spec/blob/v1.0/spec.md#subject)

Signed-off-by: Kristiyan Marinov <kristiyanm@gmail.com>
2024-11-04 09:53:36 +01:00
dependabot[bot] b54df5ca0c
Bump io.projectreactor:reactor-core from 3.5.1 to 3.6.11 (#677)
Bumps [io.projectreactor:reactor-core](https://github.com/reactor/reactor-core) from 3.5.1 to 3.6.11.
- [Release notes](https://github.com/reactor/reactor-core/releases)
- [Commits](https://github.com/reactor/reactor-core/compare/v3.5.1...v3.6.11)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-30 06:47:37 +01:00
dependabot[bot] a3decf768c
Bump org.slf4j:slf4j-simple from 1.7.36 to 2.0.16 (#674)
Bumps org.slf4j:slf4j-simple from 1.7.36 to 2.0.16.

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-simple
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 08:01:59 +01:00
dependabot[bot] 215e67f2c3
Bump rexml from 3.3.6 to 3.3.9 in /docs (#675)
Bumps [rexml](https://github.com/ruby/rexml) from 3.3.6 to 3.3.9.
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.3.6...v3.3.9)

---
updated-dependencies:
- dependency-name: rexml
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 08:01:19 +01:00
dependabot[bot] 514e00d75b
Bump rexml from 3.2.8 to 3.3.6 in /docs (#665)
Bumps [rexml](https://github.com/ruby/rexml) from 3.2.8 to 3.3.6.
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.2.8...v3.3.6)

---
updated-dependencies:
- dependency-name: rexml
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-22 14:24:28 +02:00
dependabot[bot] f7ac215bf1
Bump org.eclipse.jetty:jetty-server in /examples/basic-http (#672)
Bumps org.eclipse.jetty:jetty-server from 9.4.51.v20230217 to 9.4.55.v20240627.

---
updated-dependencies:
- dependency-name: org.eclipse.jetty:jetty-server
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-22 14:23:36 +02:00
dependabot[bot] 5f4abd144a
Bump org.apache.avro:avro from 1.11.3 to 1.11.4 in /formats/avro-compact (#671)
Bumps org.apache.avro:avro from 1.11.3 to 1.11.4.

---
updated-dependencies:
- dependency-name: org.apache.avro:avro
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-08 17:25:38 +02:00
github-actions[bot] 8d59d29bb1
Bump to 4.0.1 (#656)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierDipi@users.noreply.github.com>
2024-10-02 19:49:23 +02:00
Rohan Mallya 6ab42de007
docs: correcting import to EventFormatProvider (#658)
Signed-off-by: Rohan R Mallya <bangalorerohan@gmail.com>
2024-10-02 19:48:40 +02:00
dependabot[bot] 2e87988d0c
Bump org.apache.maven.plugins:maven-install-plugin from 2.5.1 to 3.1.3 (#664)
Bumps [org.apache.maven.plugins:maven-install-plugin](https://github.com/apache/maven-install-plugin) from 2.5.1 to 3.1.3.
- [Release notes](https://github.com/apache/maven-install-plugin/releases)
- [Commits](https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-2.5.1...maven-install-plugin-3.1.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-install-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 19:48:09 +02:00
David Simansky 6d958b69d4
Fix cloudevents-sql artifactId in bom (#669)
Signed-off-by: David Simansky <dsimansk@redhat.com>
2024-10-02 19:47:43 +02:00
dependabot[bot] 1de03ad38a
Bump org.apache.rocketmq:rocketmq-client-java from 5.0.4 to 5.0.7 (#653)
Bumps [org.apache.rocketmq:rocketmq-client-java](https://github.com/apache/rocketmq-clients) from 5.0.4 to 5.0.7.
- [Release notes](https://github.com/apache/rocketmq-clients/releases)
- [Commits](https://github.com/apache/rocketmq-clients/compare/java-5.0.4...java-5.0.7)

---
updated-dependencies:
- dependency-name: org.apache.rocketmq:rocketmq-client-java
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 14:48:32 +02:00
Pierangelo Di Pilato 4c5d0efb89
Make CloudEventValidatorProvider thread safe (#650)
Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2024-07-02 17:39:05 +02:00
github-actions[bot] 01a9111d8b
Bump to 4.0.0 in docs (#649)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierDipi@users.noreply.github.com>
2024-07-01 20:29:40 +02:00
Pierangelo Di Pilato e056d1b2d8
Allow bumping versions in `/docs` only (#648)
This will allow changing the version in the documentation website
when a new release is published.

Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2024-07-01 17:24:48 +02:00
github-actions[bot] efdf0ba866
Bump to 4.1.0-SNAPSHOT (#645)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierDipi@users.noreply.github.com>
2024-07-01 12:10:47 +02:00
github-actions[bot] bd90d903ce
Bump to 4.0.0-SNAPSHOT (#644)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierDipi@users.noreply.github.com>
2024-07-01 11:41:33 +02:00
dependabot[bot] 52a98d778c
Bump rexml from 3.2.5 to 3.2.8 in /docs (#635)
Bumps [rexml](https://github.com/ruby/rexml) from 3.2.5 to 3.2.8.
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.2.5...v3.2.8)

---
updated-dependencies:
- dependency-name: rexml
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 10:59:57 +02:00
Calum Murray 010627e784
CE SQL v1 (#641)
- add exception factory for cesql exceptions
- extend EvaluationResult to be usable internally
- expressions use results instead of a thrower interface
- functions use results instead of a thrower interface
- parser handles not equals correctly, does not eagerly evaluate when there may be an error
- parser handles integer literals properly
- updated test files to test v1 spec

Signed-off-by: Calum Murray <cmurray@redhat.com>
Co-authored-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>
2024-06-21 17:28:26 +02:00
Juan Martinez a7904823c3
fix: invalid automatic module name (#639)
Inspired by [Automatic-Module-Name: Calling All Java Library Maintainers](https://dzone.com/articles/automatic-module-name-calling-all-java-library-maintainers), I added the module names for the non-specified modules on their respective `pom.xml` file

Signed-off-by: Juan MARTINEZ <Jummartinezro@users.noreply.github.com>
2024-06-21 09:24:33 +02:00
Mickaël Schoentgen e5a35ac472
doc: update & uniformize package version (#640)
Signed-off-by: Mickaël Schoentgen <Mickael.Schoentgen@hyland.com>
2024-06-20 12:08:07 +02:00
dependabot[bot] 4d204cef89
Bump org.xmlunit:xmlunit-core from 2.9.0 to 2.10.0 in /formats/xml (#631)
Bumps [org.xmlunit:xmlunit-core](https://github.com/xmlunit/xmlunit) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/xmlunit/xmlunit/releases)
- [Changelog](https://github.com/xmlunit/xmlunit/blob/main/RELEASE_NOTES.md)
- [Commits](https://github.com/xmlunit/xmlunit/compare/v2.9.0...v2.10.0)

---
updated-dependencies:
- dependency-name: org.xmlunit:xmlunit-core
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 11:04:06 +02:00
dependabot[bot] 43afb6ceaa
Bump nokogiri from 1.16.3 to 1.16.5 in /docs (#632)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.16.3 to 1.16.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.16.3...v1.16.5)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 11:03:01 +02:00
dependabot[bot] 9c6e7fd11e
Bump io.vertx:vertx-core from 4.3.7 to 4.5.3 in /http/vertx (#622)
Bumps [io.vertx:vertx-core](https://github.com/eclipse/vert.x) from 4.3.7 to 4.5.3.
- [Commits](https://github.com/eclipse/vert.x/compare/4.3.7...4.5.3)

---
updated-dependencies:
- dependency-name: io.vertx:vertx-core
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-09 10:13:49 +02:00
github-actions[bot] 98deac1599
Bump to 3.1.0-SNAPSHOT (#613)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierDipi@users.noreply.github.com>
2024-03-26 09:59:22 +01:00
Pierangelo Di Pilato 05baf9be8a
Run workflows on any major version branch (#615)
Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2024-03-26 08:42:45 +01:00
Pierangelo Di Pilato 3add823e00
Run workflows on any major version branch (#614)
Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2024-03-26 08:39:35 +01:00
dependabot[bot] 5a03173dde
Bump org.apache.maven.plugins:maven-source-plugin from 2.2.1 to 3.3.0 (#608)
Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 2.2.1 to 3.3.0.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-2.2.1...maven-source-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-26 08:12:40 +01:00
dependabot[bot] 9ee16fb48c
Bump nokogiri from 1.13.10 to 1.16.3 in /docs (#609)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.10 to 1.16.3.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.10...v1.16.3)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-26 08:11:52 +01:00
dependabot[bot] 0db4446163
Bump com.github.hanleyt:jersey-junit from 2.1.0 to 2.2.0 (#584)
Bumps [com.github.hanleyt:jersey-junit](https://github.com/hanleyt/jersey-junit) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/hanleyt/jersey-junit/releases)
- [Commits](https://github.com/hanleyt/jersey-junit/compare/2.1.0...2.2.0)

---
updated-dependencies:
- dependency-name: com.github.hanleyt:jersey-junit
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2024-03-11 15:57:25 +01:00
touchkey 111fb55cfd
feat: Customizing Cloudevents validation (#594)
Add SPI for custom CloudEvent validation.

Signed-off-by: vbhat6 <vinayas_bhat@intuit.com>
2024-02-15 07:48:55 +01:00
Matej Vasek 55fddb35fc
feat: JSON format to assume JSON content-type where possible (#604)
Signed-off-by: Matej Vašek <mvasek@redhat.com>
2024-02-08 09:49:19 +01:00
Calum Murray 7b9d020acc
Update cesql TCK tests (#603)
Signed-off-by: Calum Murray <cmurray@redhat.com>
2024-01-31 11:51:03 +01:00
Doug Davis fb11b94f2b
Add link to CloudEvent security mailing list (#599)
Signed-off-by: Doug Davis <dug@microsoft.com>
2023-10-16 15:26:53 +02:00
Boris Stumm eaef3becdd
#588 Update jackson to 2.15.2 (#589)
Signed-off-by: Boris Stumm <bs@boris-stumm.de>
2023-10-02 10:08:48 +02:00
dependabot[bot] b30324e916
Bump org.apache.avro:avro from 1.11.2 to 1.11.3 in /formats/avro-compact (#593)
Bumps org.apache.avro:avro from 1.11.2 to 1.11.3.

---
updated-dependencies:
- dependency-name: org.apache.avro:avro
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 10:08:22 +02:00
Doug Davis 1f9fa13231
Align SDK governance docs (#590)
Related to https://github.com/cloudevents/spec/pull/1226

Signed-off-by: Doug Davis <dug@microsoft.com>
2023-09-28 09:29:59 +02:00
dependabot[bot] a135755ec6
Bump jackson-dataformat-yaml from 2.11.2 to 2.15.2 (#577)
Bumps [jackson-dataformat-yaml](https://github.com/FasterXML/jackson-dataformats-text) from 2.11.2 to 2.15.2.
- [Commits](https://github.com/FasterXML/jackson-dataformats-text/compare/jackson-dataformats-text-2.11.2...jackson-dataformats-text-2.15.2)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 09:19:35 +02:00
dependabot[bot] 677a2c2628
Bump jetty-server in /examples/basic-http (#579)
Bumps [jetty-server](https://github.com/eclipse/jetty.project) from 9.4.41.v20210516 to 9.4.51.v20230217.
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.41.v20210516...jetty-9.4.51.v20230217)

---
updated-dependencies:
- dependency-name: org.eclipse.jetty:jetty-server
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 09:19:06 +02:00
dependabot[bot] 826e099fc0
Bump io.openliberty.arquillian:arquillian-liberty-managed-jakarta-junit (#582)
Bumps [io.openliberty.arquillian:arquillian-liberty-managed-jakarta-junit](https://github.com/OpenLiberty/arquillian-liberty-dependencies) from 2.1.0 to 2.1.4.
- [Release notes](https://github.com/OpenLiberty/arquillian-liberty-dependencies/releases)
- [Commits](https://github.com/OpenLiberty/arquillian-liberty-dependencies/compare/arquillian-liberty-jakarta-dependencies-2.1.0...arquillian-liberty-jakarta-dependencies-2.1.4)

---
updated-dependencies:
- dependency-name: io.openliberty.arquillian:arquillian-liberty-managed-jakarta-junit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 09:18:34 +02:00
dependabot[bot] 76366338fc
Bump truth-proto-extension from 1.1 to 1.1.5 (#580)
Bumps truth-proto-extension from 1.1 to 1.1.5.

---
updated-dependencies:
- dependency-name: com.google.truth.extensions:truth-proto-extension
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-20 18:03:41 +02:00
Alex Collins 4ef304115a
[working-draft] Support Avro Compact Format (#578)
Add support for working-draft spec Avro compact format: 777d0c0398

Signed-off-by: Alex Collins <alex_collins@intuit.com>
2023-07-20 18:02:59 +02:00
dependabot[bot] 582feed520
Bump maven-gpg-plugin from 1.6 to 3.1.0 (#564)
Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 1.6 to 3.1.0.
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-1.6...maven-gpg-plugin-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-23 12:08:54 +02:00
github-actions[bot] 5ef1088a19
Bump to 3.0.0-SNAPSHOT (#571)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierDipi@users.noreply.github.com>
2023-05-23 10:55:49 +02:00
Aaron Ai 698cdf7ad4
feat: add rocketmq binding (#554)
Spec details: a6978cf562/rocketmq-cloudevents-binding/rocketmq-transport-binding.md

Signed-off-by: Aaron Ai <yangkun.ayk@alibaba-inc.com>
2023-05-23 10:49:08 +02:00
skepticoitusInteruptus 4ebeab0e0f
Refactor to Facilitate Decoupling from Concrete Implementations of EventFormat (#539)
- Introduce ContentType enum
- Resolve formats by using the ContentType enum

Signed-off-by: Randi Sheaffer-Klass <97033958+skepticoitusInteruptus@users.noreply.github.com>
2023-04-21 10:41:10 +02:00
Jem Day 4c81f3eacc
Make ProtoCloudEventData consistent (#535)
Modified ProtoCloudEventData to always return a 
Protobuf Any object - this ensures it is coherent with
the Protobuf CloudEvent format specification.

It remains possible to wrap any Protobuf 'Message'
object directly (which includes an 'Any') as a
convienience to reduce application code.

Signed-off-by: Jem Day <Jem.Day@cliffhanger.com>
2023-03-10 09:35:24 +01:00
Pierangelo Di Pilato 569e025cf0
Fix javadoc build (#529) (#534)
Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2023-03-06 18:25:53 +01:00
Jem Day 3614a4f5f4
Fixed Protobuf data corruption for CloudEvent serialized/deserialized several times (#524)
Fixed issue where mutiple serialize/de-serialize operations
would result in corrupted data if the data was a protobuf
message object.

- Introduced equality checks for ProtoDataWrapper.
- Refactored and cleaned up data-wrappers.

Fixes https://github.com/cloudevents/sdk-java/issues/523

Signed-off-by: Jem Day <Jem.Day@cliffhanger.com>
2023-02-27 11:48:07 +01:00
mxsm d64aff7327
[#521] Remove unused imports (#522)
Signed-off-by: mxsm <ljbmxsm@gmail.com>
2023-02-20 18:06:28 +01:00
dependabot[bot] d1cff75230
Bump activesupport from 6.0.6 to 6.0.6.1 in /docs (#517)
Bumps [activesupport](https://github.com/rails/rails) from 6.0.6 to 6.0.6.1.
- [Release notes](https://github.com/rails/rails/releases)
- [Changelog](https://github.com/rails/rails/blob/v7.0.4.2/activesupport/CHANGELOG.md)
- [Commits](https://github.com/rails/rails/compare/v6.0.6...v6.0.6.1)

---
updated-dependencies:
- dependency-name: activesupport
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-20 08:42:50 +01:00
Ruben Romero Montes 1591cb337a
[#465] Upgrade Quarkus examples with binary and structured events (#515)
Signed-off-by: ruromero <rromerom@redhat.com>
2023-01-24 16:54:22 +01:00
Pierangelo Di Pilato f71303b7b7
Switch default branch to main (#506)
Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2023-01-12 19:03:51 +01:00
Pierangelo Di Pilato d59b33307a
Run tests before deploy on Java 17 (#504)
Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2023-01-10 16:49:47 +01:00
dependabot[bot] e0d1961f35
Bump nokogiri from 1.13.9 to 1.13.10 in /docs (#496)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.9 to 1.13.10.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.9...v1.13.10)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 16:41:29 +01:00
dependabot[bot] 7c6b52ab30
Bump reactor-core from 3.4.21 to 3.5.1 (#499)
Bumps [reactor-core](https://github.com/reactor/reactor-core) from 3.4.21 to 3.5.1.
- [Release notes](https://github.com/reactor/reactor-core/releases)
- [Commits](https://github.com/reactor/reactor-core/compare/v3.4.21...v3.5.1)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 16:10:42 +01:00
Jem Day 433ec5b274
Initial Implementation of XML Format (#448)
Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>
Signed-off-by: Jem Day <Jem.Day@cliffhanger.com>
2023-01-10 09:48:36 +01:00
Doug Davis 40fe91a5e0
Use UTF-8 when using getBytes (#491)
Closes #488

Signed-off-by: Doug Davis <dug@microsoft.com>
2023-01-05 18:01:14 +01:00
Pierangelo Di Pilato a43f90f4e2
Create dependabot.yml 2023-01-02 15:19:06 +01:00
dependabot[bot] e488269510
Bump nokogiri from 1.13.6 to 1.13.9 in /docs (#486)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.6 to 1.13.9.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.6...v1.13.9)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 15:11:24 +01:00
Fabio José 7d50c7fc7a
Bump Vertx to 4.3.7 (#495)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-3167773

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-01-02 15:10:38 +01:00
Averi Kitsch f1a86af656
Fix curl command for Spring example (#478)
Signed-off-by: Averi Kitsch <akitsch@google.com>
2023-01-02 13:36:30 +01:00
Doug Davis 354f7a16ef
Upgrade kafka, protobuf, and vert.x versions (#492)
Closes #489

Signed-off-by: Doug Davis <dug@microsoft.com>
2022-12-09 12:35:19 +01:00
Pierangelo Di Pilato 9132a13d81
Remove deprecated constructor usage for JsonCloudEventData (#483)
Fixes #482

Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2022-10-12 08:58:41 +02:00
dependabot[bot] a491c85eb2
Bump tzinfo from 1.2.8 to 1.2.10 in /docs (#467)
Bumps [tzinfo](https://github.com/tzinfo/tzinfo) from 1.2.8 to 1.2.10.
- [Release notes](https://github.com/tzinfo/tzinfo/releases)
- [Changelog](https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md)
- [Commits](https://github.com/tzinfo/tzinfo/compare/v1.2.8...v1.2.10)

---
updated-dependencies:
- dependency-name: tzinfo
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-12 08:56:14 +02:00
Frédéric Déléchamp 6362bfbcd6
Strip parameters from data content types to assess if it's JSON format (#484)
Signed-off-by: Frederic Delechamp <fdelechamp@guidewire.com>
2022-10-06 10:42:37 +02:00
Alex Butcher f08a099ed9
Restful-ws jakarta ee9 namespace support (#469)
* Replace javax restful-ws namespace usage with jakarata in own module
* Add microprofile with openliberty example using new jar
* Update gitignore to cover all copied directories
* Update Jersey Version to support jakarta.* namespace packages
* Port jersey integration tests from javax.* to jakarta.*
* Undo changes to existing integration test package names
* Add Integration test for Microprofile/Liberty for Jee9 package
* Add documentation for new Jakarta package

Signed-off-by: alex-butcher <21243172+abutch3r@users.noreply.github.com>
2022-09-27 09:16:03 +02:00
Vikram Vuppla 4139fb7e57
Fix typo in word Covert (#480)
Signed-off-by: Vikram Vuppla <naga.vicky@gmail.com>
2022-09-19 17:31:31 +02:00
Gerard Klijs adde53c817
Correct URL to naming-conventions (#477)
Signed-off-by: Gerard Klijs <gerard.klijs@axoniq.io>
2022-09-14 15:46:09 +02:00
Jorge Oliva 0dc10251ff
Fix example in "Materialize an Extension" (#475)
Was using `ExtensionParser` instead `ExtensionProvider`

Signed-off-by: Jorge Oliva <Jorge.OlivaFernandez@santander.co.uk>
2022-09-14 11:39:25 +02:00
github-actions[bot] b9eaa2fcaa
Bump to 2.5.0-SNAPSHOT (#474)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: pierDipi <pierdipi@redhat.com>
2022-09-06 15:52:34 +02:00
Isaac Aymerich f8d27b08bf
Support dynamic JSON data content type (#471)
Now checks if `datacontenttype` matches the regex:

`^(application|text)\/([a-zA-Z]+\+)?json$")`

This regex support 
`application/foobar+json`
or standard
```
application/json
text/json
```

Signed-off-by: Isaac Aymerich <isaac.aymerich@roche.com>
2022-09-05 13:14:38 +02:00
Matej Vasek 9125136530
chore: update Quarkus example (#466)
* Server accepts both: binary and structured encoded events.
* Emitter contains comment describing how to switch between binary and
  structured encoding for emitted events.

Signed-off-by: Matej Vasek <mvasek@redhat.com>
2022-07-19 12:27:44 +02:00
Gustavo Tedesco f35e6e610a
CVE-2020-36518 - bump jackson from 2.11.2 to 2.13.3 (#464)
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-36518

Signed-off-by: Gustavo Tedesco <gustavo.tedesco@unico.io>
2022-07-13 17:16:38 +02:00
Pierangelo Di Pilato 45ec85f8c1
Optimize `isCloudEventsHeader` check (#445)
Instead of using:
```java
key.substring(0, CE_PREFIX.length()).toLowerCase().startsWith(CE_PREFIX);
```
we can just use:
```java
key.regionMatches(true /* ignoreCase */, 0, CE_PREFIX, 0, CE_PREFIX.length());
```

Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2022-07-13 10:18:17 +02:00
dependabot[bot] 1d87fb7191
Bump nokogiri from 1.13.3 to 1.13.6 in /docs (#457)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.3 to 1.13.6.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.3...v1.13.6)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-25 16:06:16 +02:00
Snyk bot 8f9b741306
[Snyk] Security upgrade io.vertx:vertx-core from 4.0.0 to 4.2.5 (#455)
* fix: http/vertx/pom.xml to reduce vulnerabilities

The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1020439
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1070799
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1082234
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1082235
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1082236
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1083991
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1089809
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1317097
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1584063
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-1584064
- https://snyk.io/vuln/SNYK-JAVA-IONETTY-2314893

* Bump Vert.x to 4.2.5

Co-authored-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2022-04-08 11:13:07 +02:00
dependabot[bot] 2dd8ba95dd
Bump nokogiri from 1.12.5 to 1.13.3 in /docs (#447)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.12.5 to 1.13.3.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.12.5...v1.13.3)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-01 19:01:24 +02:00
Pierangelo Di Pilato 1c29726e8c
Add `CONTRIBUTING.md` and `MAINTAINERS.md` files (#454)
These 2 new files are based on the existing `pr_guidelines.md`
and `maintainers_guide.md`

Signed-off-by: Pierangelo Di Pilato <pierdipi@redhat.com>
2022-04-01 19:00:37 +02:00
mEstrazulas 6681205733
Fix Spring structured example (#451)
Signed-off-by: Micael Vianna <estrazulas@gmail.com>
Signed-off-by: Micael Estrazulas Vianna <m.vianna@kigroup.de>
2022-03-18 23:24:37 +01:00
Jem Day a4bc7a8368
Protobuf: Enhance textual content-types detection (#444)
- Move content-type introspection in a separate support class.
- Add unit tests to ensure introspection is correct.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>
2022-01-31 10:18:22 +01:00
github-actions[bot] 4784f03e8c
Bump to 2.4.0-SNAPSHOT (#439)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: pierDipi <pierdipi@redhat.com>
2021-12-21 12:18:07 +01:00
Pierangelo Di Pilato ace6859ae0
Bump version to 2.3.0 (#437)
Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>
2021-12-21 12:06:57 +01:00
Pierangelo Di Pilato cc786251d5
Handle NullNode for optional attributes in Jackson CloudEventDeserializer (#432)
In `getOptionalStringNode` we should handle `JsonNode`s that are
instances of `NullNode`.

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>
2021-12-21 11:22:02 +01:00
Myeonghyeon-Lee ceb06757a3
Ignore invalid extension names in jackson CloudEventDeserializer (#429)
Signed-off-by: mhyeon-lee <mhyeon.lee@navercorp.com>
2021-12-10 10:26:47 +01:00
Pierangelo Di Pilato 8d91cdaee6
Run tests with Java 17 (#426)
Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>
2021-12-01 09:05:02 +01:00
Pierangelo Di Pilato d00ad967c0
Fix the Java Doc build (#424)
- https://vertx.io/docs/apidocs/ returns 404, so removing it
- Fix Java Doc error for missing `@param`

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>
2021-11-17 16:55:27 +01:00
Dave Syer 9231e6d230
Add example of Spring WebClient usage (#418)
- Add example of WebClient usage
- Add additional test case with WebClient usage

Signed-off-by: Dave Syer <dsyer@vmware.com>
2021-11-17 16:25:59 +01:00
Joke de Buhr a94bc5c81c
Close input stream on CloudEventHttpMessageReader (#421)
Signed-off-by: Joke de Buhr <joke.debuhr@eventim.de>
2021-11-03 09:54:38 +01:00
Dmitrii Bocharov 32adfe9123
Fix NPE in CloudEventDeserializer when deserializing header with null value (#415)
Signed-off-by: Dmitrii Bocharov <dmitrii.bocharov@embedit.cz>
2021-11-03 08:28:54 +01:00
dependabot[bot] 0277ee4ae4
Bump spring-framework-bom in /examples/restful-ws-spring-boot (#423)
Bumps [spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.2.8.RELEASE to 5.2.9.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.8.RELEASE...v5.2.9.RELEASE)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-03 08:26:35 +01:00
dependabot[bot] 202849307c
Bump addressable from 2.7.0 to 2.8.0 in /docs (#406)
Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/sporkmonger/addressable/releases)
- [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.0)

---
updated-dependencies:
- dependency-name: addressable
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-03 08:07:20 +01:00
dependabot[bot] 624ac693d8
Bump nokogiri from 1.11.5 to 1.12.5 in /docs (#419)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.5 to 1.12.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.5...v1.12.5)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-03 08:06:43 +01:00
dependabot[bot] 5a323942d3
Bump jetty-server in /examples/basic-http (#403)
Bumps [jetty-server](https://github.com/eclipse/jetty.project) from 9.4.38.v20210224 to 9.4.41.v20210516.
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.38.v20210224...jetty-9.4.41.v20210516)

---
updated-dependencies:
- dependency-name: org.eclipse.jetty:jetty-server
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-05 12:22:52 +02:00
dependabot[bot] 1587708805
Bump spring-framework-bom (#382)
Bumps [spring-framework-bom](https://github.com/spring-projects/spring-framework) from 5.2.8.RELEASE to 5.2.9.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v5.2.8.RELEASE...v5.2.9.RELEASE)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-05 12:22:46 +02:00
Francesco Guardiani 06c4ec5385
Moved exception factory methods internally (#402)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-07-05 11:43:46 +02:00
Nicolas Vervelle 73a3c370d5
build: provide a Bill of Materials artifact for easier integration in projects (#405)
Signed-off-by: Nicolas Vervelle <nicolas.vervelle@quicksign.com>
2021-06-28 09:30:41 +02:00
github-actions[bot] 722f5205b3
Bump to 2.3.0-SNAPSHOT (#400)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-06-17 12:18:55 +02:00
github-actions[bot] 8ad857d8c7
Bump to 2.2.0 (#399)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-06-17 12:05:04 +02:00
Francesco Guardiani baa9b5927a
[CESQL] Reorganize package implementation classes (#397)
* Move classes around to improve package organization

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Removed bad imports

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-06-15 10:31:14 +02:00
Francesco Guardiani c41a2c3ba7
Cleanup CloudEventUtils (#398)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-06-14 16:30:07 +02:00
Francesco Guardiani 3651cdae18
Add a method to simplify casting (#396)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-06-07 08:36:02 +02:00
dependabot[bot] ee4c85b1a1
Bump nokogiri from 1.11.1 to 1.11.5 in /docs (#393)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.1 to 1.11.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.1...v1.11.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-04 09:41:26 +02:00
Francesco Guardiani a0b0835180
[CESQL] Constant folding (#392)
* Added visitor for the expressions

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* First constant folding draft

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Constant folding for unary expressions

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More testing
Constant folding for exists expression

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Little mistake

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added a ParserBuilder

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-06-04 09:19:38 +02:00
Pei-Tang Huang 687e03bac5
Update the link to http4k Cloud Events module. (#394)
Signed-off-by: Pei-Tang Huang <tangtheone@gmail.com>
2021-05-26 09:36:30 +02:00
Francesco Guardiani 208b18c299
Build release branches too (#386)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-05-06 14:07:52 +02:00
Francesco Guardiani 9d45943844
Fix like expression (#381)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-05-03 10:05:26 +02:00
shnplr 0a1a03db64
fix: Update encoding for structured event (#384)
Signed-off-by: Paul Strachan <paul.strachan@det.nsw.edu.au>
2021-05-03 09:39:48 +02:00
dependabot[bot] 7f355d10c1
Bump rexml from 3.2.4 to 3.2.5 in /docs (#383)
Bumps [rexml](https://github.com/ruby/rexml) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.2.4...v3.2.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-03 09:34:47 +02:00
Francesco Guardiani 3234e30e55
CESQL Benchmark (#380)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-04-30 11:01:02 +02:00
github-actions[bot] c8f10e9215
Bump to 2.2.0-SNAPSHOT (#378)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-04-28 15:50:41 +02:00
github-actions[bot] ba9ccad5d2
Bump to 2.1.0 (#377)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-04-28 15:24:41 +02:00
Francesco Guardiani 78355bb225
Fix #326 (#376)
Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-04-28 15:15:45 +02:00
Francesco Guardiani 2730ae4a13
Expression language (#363)
* Configured the sql package

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Bootstrap implementation

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Literal done

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More progress

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Progress

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Sync contract

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Fix type cohercion for event type system

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* In expression + sync grammar

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Implemented binary expressions

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Implemented Like expression

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Big refactor

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More testing
Fix math

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Implemented all the functions!

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Refactored logical expressions implementation
More testing

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More coverage and tests

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Fixed ConcatFunction and added ConcatWSFunction

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Fixed IN type casting

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added ABS function

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Fix SUBSTRING implementation

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More nits

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* WIP Javadoc-ing

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Fix division by 0

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Bootstrapped TCK

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added comparison operators to tck

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added logical operators, case sensitivity and casting functions

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Copied all the tests to the tck

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Removed Java tests now covered by the TCK

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added integer builtin test case

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added fail fast evaluation mode

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More changes
More Javadoc

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Typo

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Fix bad javadoc

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Another CONCAT_WS test case

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Import yaml just for testing

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
2021-04-28 14:58:55 +02:00
Johan Haleby 30fd6769eb
fix: Adding withoutData, withoutDataContentType and withoutDataSchema to CloudEventBuilder (#374)
Signed-off-by: Johan Haleby <johan.haleby@gmail.com>
2021-04-23 13:59:39 +02:00
dependabot[bot] ff07dd8315
Bump jetty-server in /examples/basic-http (#372)
Bumps [jetty-server](https://github.com/eclipse/jetty.project) from 9.4.35.v20201120 to 9.4.38.v20210224.
- [Release notes](https://github.com/eclipse/jetty.project/releases)
- [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.35.v20201120...jetty-9.4.38.v20210224)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-19 12:38:51 +02:00
Erik Paulson 928ebcfd6f
formats: Add support for protobuf format (#348)
* formats: Add support for protobuf format

Adds support for the Protocol Buffer CloudEvent format defined at
https://github.com/cloudevents/spec/blob/v1.0.1/protobuf-format.md.

Compiles the Proto3 file taken from the spec repo into generated Java
protobuf classes. These classes are used to convert the SDK
representation of a CloudEvent to and from the protobuf format.

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* Address feedback in PR #348

- Adds service file for event format autoloading
- Addresses some field access issues
- Treats unset fields as omitted
- Updates and adds documentation

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* Add missing attribute writer methods for CloudEventBuilders

Without these methods, binary attributes are interpreted as
Strings instead of byte[].

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* Added test data files.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* - Now executes tests related to wire-format files.
- Supports V03 dialect

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* - Added new ProtoCloudEventData construct to support proto message based data.
- Added some more test files.

- When the PR related to binary context attributes is merged we can extend the
test use-cases appropriately.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* - Merged changes related to binary context attributes.
- Modified proto format to process binary context attributes
- Added CloudEventData varient to hold proto messages (requires tests)
- Will add further tests once the failing test is addressed

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Added test for protobuf data

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Indicate that v0.3 events are supported by Protobuf Format

Even though the protobuf spec came out for v1, the attributes are
fairly easily mapped back to v0.3.

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* Add missing comments; fix formatting; minor refactoring

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* Create a full Protobuf CloudEventWriter

Converts the ProtoContextWriter class to a ProtoCloudEventWriter class
and modifies the format code to use it instead of manually writing
data to the output.

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* - Addressed Review Comments.
- Introduced a default ProtoDataWrapper
- Tests updated.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Address Review Comments

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Test cleanup and timezone testing

This does some tweaking to tests by moving to using assertj and fixing
whitespace. It also adds a new test to ensure that timezones are handled
correctly.

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

* Formatting cleanup

- Remove unecessary whitespace
- Fix Javadocs
- Delete unused code

Signed-off-by: Erik Paulson <epaulson@apexclearing.com>

Co-authored-by: Day, Jeremy(jday) <jday@paypal.com>
2021-04-19 09:24:26 +02:00
Pierangelo Di Pilato a4613c00d2
Avoid allocating an array on extension validation (#367)
Signed-off-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>
2021-04-06 10:14:08 +02:00
Pierangelo Di Pilato 69f0e20549
CloudEvents attribute names SHOULD NOT exceed 20 chars (#366)
As per spec [1], attribute names SHOULD NOT and not MUST NOT
exceed 20 characters in length.

[1] https://github.com/cloudevents/spec/blob/master/spec.md#attribute-naming-conventionthis

Signed-off-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>
2021-04-06 10:00:55 +02:00
Jem Day e2b13109e4
Throw exceptions when atempting to handling unsupport CloudEvent formats. (#362)
- Modfy logic that selects between structured and binary modes during reception.
- Introduced new test scenarios to veify behavior.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>
2021-03-26 09:55:23 +01:00
Jem Day 5e3bfc890f
Specification Compliant handling of numeric context attributes (#358)
* - Added tests case to verify expected handling of numeric context attributes
- Updated serializer.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* - Added @deprecated marker for CloudEventContextWriter.set(name, Number)
- Added use of new method for JSON serializer.

Cleanup of deprecated implementations can occur independantly.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Addressed Review Comments

- Now throws exception when non specification compliant numeric
  attribute values are received during deserialization.

- Added test cases to verify deserialization exceptions.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Address Review Comments

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Address Review Comment

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>
2021-03-24 16:58:33 +01:00
Jem Day 13f8b56618
Introduced support for Binary attribute types. (#353)
* Introduced support for Binary attribute types.

Added test data example
Added unit-test for JSON Format

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* documentation tweak

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* - Addressed review comment.
- Removed the withContextAttribute(string, Integer).
   - This should be a seperate PR, was mixed-in by accident.

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>

* Address review comments

Signed-off-by: Day, Jeremy(jday) <jday@paypal.com>
2021-03-10 11:29:38 +01:00
Dave Syer a419d8bba3
Add Spring Cloud Function sample (#356)
* Add Spring Cloud Function sample

Signed-off-by: Dave Syer <dsyer@vmware.com>

* Fix example curl command with structured event

Signed-off-by: Dave Syer <dsyer@vmware.com>
2021-03-08 15:08:16 +01:00
Dave Syer 47bed5616d
Flesh out the docs in the Spring module a bit (#355)
Signed-off-by: Dave Syer <dsyer@vmware.com>
2021-03-08 14:39:17 +01:00
Dave Syer baba37ccfd
Regularize copyright headers (#354)
Signed-off-by: Dave Syer <dsyer@vmware.com>
2021-03-05 10:19:47 +01:00
dependabot[bot] 32bcdcd3b9
Bump nokogiri from 1.10.10 to 1.11.1 in /docs (#347)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.1.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-05 09:18:32 +01:00
Dave Syer 8b382734d9
Add support for RSockets with Spring (#349)
* Add support for RSockets with Spring

Also generically can support structured events with any Spring
API that works with Encoder and Decoder. There's a sample for
the RSocket case with a simple request-response echo server.

Signed-off-by: Dave Syer <dsyer@vmware.com>

* Use supported mime types from format provider

Signed-off-by: Dave Syer <dsyer@vmware.com>
2021-03-05 09:18:19 +01:00
Dave Syer f05418cba9
Allow user to enumerate supported content types (#350)
Signed-off-by: Dave Syer <dsyer@vmware.com>
2021-03-01 11:02:54 +01:00
David Denton 23cd08fcfd
Fix #344 - add http4k references to docs (#345)
Signed-off-by: David Denton <denton.david@gmail.com>
2021-02-15 09:42:13 +01:00
github-actions[bot] 70782da2c2
Bump to 2.1.0-SNAPSHOT (#346)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-02-15 09:19:58 +01:00
github-actions[bot] 48fc69e058
Bump to 2.0.0 (#343)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-02-15 09:09:09 +01:00
Mark Scott e7e6e46bd5
fix: prevent NPE on deserializing JSON containing invalid `specversion` value (#342)
* fix: prevent NPE on deserializing JSON containing invalid `specversion` value

Signed-off-by: Mark Scott <mark@codebrewer.org>

* refactor: move test per PR review comment

Signed-off-by: Mark Scott <mark@codebrewer.org>
2021-02-03 08:30:29 +01:00
Francesco Guardiani e523bfbfbf
Rename extension (#339)
* Fixed broken links

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Renamed Extension to CloudEventExtension

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2021-02-02 08:32:43 +01:00
Thomas Qvarnström 12eee4da6e
Use scheduler instead of StartupEvent. Fixes #332 (#333)
Signed-off-by: Thomas Qvarnström <tqvarnst@redhat.com>
2020-12-16 11:36:28 +01:00
Alfusainey Jallow d49ff9f69d
update AMQP docs (#331)
Signed-off-by: Alfusainey Jallow <alf.jallow@gmail.com>
2020-12-14 11:08:41 +01:00
github-actions[bot] 611f2292a7
Bump to 2.0.0-SNAPSHOT (#329)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: slinkydeveloper <slinkydeveloper@users.noreply.github.com>
2020-12-11 11:15:02 +01:00
359 changed files with 15397 additions and 503 deletions

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "maven"
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View File

@ -4,6 +4,8 @@ on:
push:
branches:
- master
- main
- '[0-9]+.[0-9]+'
jobs:
test:
@ -11,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 8, 11 ]
java: [ 8, 11, 17 ]
steps:
- uses: actions/checkout@v2
- name: Setup java
@ -19,8 +21,9 @@ jobs:
with:
java-version: ${{ matrix.java }}
- run: |
mvn clean install -DskipTests -B
mvn verify -B
./mvnw clean install -DskipTests -B
./mvnw verify -B
deploy:
runs-on: ubuntu-latest
name: Deploy
@ -31,13 +34,13 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 8
server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml
server-id: central # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
- name: Publish to Apache Maven Central
run: mvn clean deploy -Drelease -DskipTests -B
run: ./mvnw clean deploy -Drelease -DskipTests -B
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}

View File

@ -5,6 +5,14 @@ on:
version:
description: 'Version to bump (without prepending "v")'
required: true
maven-modules:
description: "Whether to bump versions in pom.xml files"
type: choice
required: true
default: 'true'
options:
- 'true'
- 'false'
jobs:
bump:
@ -19,7 +27,8 @@ jobs:
with:
java-version: 8
- name: Bump version using Maven
run: 'mvn versions:set -DnewVersion=$NEW_VERSION -DgenerateBackupPoms=false -B'
if: ${{ inputs.maven-modules == 'true' }}
run: './mvnw versions:set -DnewVersion=$NEW_VERSION -DgenerateBackupPoms=false -B'
- name: Bump version in docs
if: ${{ !endsWith(github.event.inputs.version, 'SNAPSHOT') }}
run: 'find . -type f -name "*.md" -exec sed -i -e "s+<version>[a-zA-Z0-9.-]*<\/version>+<version>$NEW_VERSION</version>+g" {} +'

View File

@ -4,20 +4,24 @@ on:
pull_request:
branches:
- master
- main
- '[0-9]+.[0-9]+'
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 8, 11 ]
java: [ 8, 11, 17 ]
name: Java ${{ matrix.java }} Test
steps:
- uses: actions/checkout@v2
- name: Setup java
uses: actions/setup-java@v1
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
- run: |
mvn clean install -DskipTests -B
mvn verify -B
./mvnw clean install -DskipTests -B
./mvnw verify -B
./mvnw javadoc:javadoc

2
.gitignore vendored
View File

@ -45,3 +45,5 @@ _site/
# MacOS
*.DS_Store
/http/restful-ws-jakarta/src/main/*

View File

@ -1,4 +1,19 @@
# Pull Request Guidelines
# Contributing to CloudEvents' Java SDK
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
We welcome contributions from the community! Please take some time to become
acquainted with the process before submitting a pull request. There are just
a few things to keep in mind.
# Pull Requests
Typically, a pull request should relate to an existing issue. If you have
found a bug, want to add an improvement, or suggest an API change, please
create an issue before proceeding with a pull request. For very minor changes
such as typos in the documentation this isn't really necessary.
## Pull Request Guidelines
Here you will find step by step guidance for creating, submitting and updating
a pull request in this repository. We hope it will help you have an easy time
@ -8,7 +23,7 @@ your code. Thanks for getting involved! :rocket:
* [Getting Started](#getting-started)
* [Branches](#branches)
* [Commit Messages](#commit-messages)
* [Staying current with master](#staying-current-with-master)
* [Staying current with main](#staying-current-with-main)
* [Submitting and Updating a Pull Request](#submitting-and-updating-a-pull-request)
* [Congratulations!](#congratulations)
@ -32,7 +47,7 @@ organized.
```console
git fetch upstream
git reset --hard upstream/master
git reset --hard upstream/main
git checkout FETCH_HEAD
git checkout -b 48-fix-http-agent-error
```
@ -87,19 +102,19 @@ Date: Thu Feb 2 11:41:15 2018 -0800
Notice the `Author` and `Signed-off-by` lines match. If they don't your PR will
be rejected by the automated DCO check.
## Staying Current with `master`
## Staying Current with `main`
As you are working on your branch, changes may happen on `master`. Before
As you are working on your branch, changes may happen on `main`. Before
submitting your pull request, be sure that your branch has been updated
with the latest commits.
```console
git fetch upstream
git rebase upstream/master
git rebase upstream/main
```
This may cause conflicts if the files you are changing on your branch are
also changed on master. Error messages from `git` will indicate if conflicts
also changed on main. Error messages from `git` will indicate if conflicts
exist and what files need attention. Resolve the conflicts in each file, then
continue with the rebase with `git rebase --continue`.
@ -116,15 +131,15 @@ git push -f origin 48-fix-http-agent-error
Before submitting a pull request, you should make sure that all of the tests
successfully pass.
Once you have sent your pull request, `master` may continue to evolve
before your pull request has landed. If there are any commits on `master`
Once you have sent your pull request, `main` may continue to evolve
before your pull request has landed. If there are any commits on `main`
that conflict with your changes, you may need to update your branch with
these changes before the pull request can land. Resolve conflicts the same
way as before.
```console
git fetch upstream
git rebase upstream/master
git rebase upstream/main
# fix any potential conflicts
git push -f origin 48-fix-http-agent-error
```
@ -141,7 +156,7 @@ for details.
```console
git commit -m "fixup: fix typo"
git rebase -i upstream/master # follow git instructions
git rebase -i upstream/main # follow git instructions
```
Once you have rebased your commits, you can force push to your fork as before.

5
MAINTAINERS.md Normal file
View File

@ -0,0 +1,5 @@
# Maintainers
Current active maintainers of this SDK:
- [Pierangelo Di Pilato](https://github.com/pierDipi)

View File

@ -1,17 +1,5 @@
# Maintainer's Guide
## Release Process
The release process is automated with Github actions. In order to perform a release:
1. Check if master CI pass.
1. Open the Github repository main page and go in the tab "Actions". Trigger the workflow "Bump version" and insert the new version to release. This will create a new release PR.
1. Check the release PR, merge it and cleanup the created branch.
1. Wait for the CI to complete the deploy of the modules to OSSRH.
1. Using the Github UI, create a new release, specifying the release notes and the tag to use.
1. Trigger again the workflow "Bump version" to bump versions back to a snapshot version.
1. Check the snapshot release PR, merge it and cleanup the created branch.
## Tips
Here are a few tips for repository maintainers.
@ -38,14 +26,14 @@ When landing pull requests, be sure to check the first line uses an appropriate
## Branch Management
The `master` branch is the bleeding edge. New major versions of the module
The `main` branch is the bleeding edge. New major versions of the module
are cut from this branch and tagged. If you intend to submit a pull request
you should use `master HEAD` as your starting point.
you should use `main HEAD` as your starting point.
Each major release will result in a new branch and tag. For example, the
release of version 1.0.0 of the module will result in a `v1.0.0` tag on the
release commit, and a new branch `v1.x.y` for subsequent minor and patch
level releases of that major version. However, development will continue
apace on `master` for the next major version - e.g. 2.0.0. Version branches
apace on `main` for the next major version - e.g. 2.0.0. Version branches
are only created for each major version. Minor and patch level releases
are simply tagged.

View File

@ -43,13 +43,18 @@ Supported features of the specification:
| - [Jakarta Restful WS](http/restful-ws) | :heavy_check_mark: | :heavy_check_mark: |
| - [Basic](http/basic) | :heavy_check_mark: | :heavy_check_mark: |
| - [Spring](spring) | :heavy_check_mark: | :heavy_check_mark: |
| - [http4k][http4k]<sup></sup>| :heavy_check_mark: | :heavy_check_mark: |
| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
| - [Jackson](formats/json-jackson) | :heavy_check_mark: | :heavy_check_mark: |
| Protobuf Event Format | :heavy_check_mark: | :heavy_check_mark: |
| - [Proto](formats/protobuf) | :heavy_check_mark: | :heavy_check_mark: |
| [Kafka Protocol Binding](kafka) | :heavy_check_mark: | :heavy_check_mark: |
| MQTT Protocol Binding | :x: | :x: |
| NATS Protocol Binding | :x: | :x: |
| Web hook | :x: | :x: |
<sub>† Source/artifacts hosted externally</sub>
## Documentation
Documentation is available at https://cloudevents.github.io/sdk-java/.
@ -58,7 +63,10 @@ Javadocs are available on [javadoc.io](https://www.javadoc.io):
- [cloudevents-api](https://www.javadoc.io/doc/io.cloudevents/cloudevents-api)
- [cloudevents-core](https://www.javadoc.io/doc/io.cloudevents/cloudevents-core)
- [cloudevents-avro-compact](https://www.javadoc.io/doc/io.cloudevents/cloudevents-avro-compact)
- [cloudevents-json-jackson](https://www.javadoc.io/doc/io.cloudevents/cloudevents-json-jackson)
- [cloudevents-protobuf](https://www.javadoc.io/doc/io.cloudevents/cloudevents-protobuf)
- [cloudevents-xml](https://www.javadoc.io/doc/io.cloudevents/cloudevents-xml)
- [cloudevents-http-basic](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-basic)
- [cloudevents-http-restful-ws](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws)
- [cloudevents-http-vertx](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-vertx)
@ -70,9 +78,9 @@ You can check out the examples in the [examples](examples) directory.
## Used By
| [Occurrent](https://occurrent.org) | [Knative Eventing](https://github.com/knative-sandbox/eventing-kafka-broker) |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <a href="https://occurrent.org"><img src="https://raw.githubusercontent.com/johanhaleby/occurrent/master/occurrent-logo-196x196.png" width="98" height="98" alt="Occurrent" title="Occurrent - Event Sourcing Utilities for the JVM"></img></a> | <a href="https://github.com/knative-sandbox/eventing-kafka-broker"><img src="https://cloudevents.io/img/logos/integrations/knative.png" height="98"></img></a> |
| [Occurrent](https://occurrent.org) | [Knative Eventing](https://github.com/knative-sandbox/eventing-kafka-broker )| [http4k][http4k] |
| ---------------------------------- | ---------------------------------------------------------------------------- | ---------------|
| <a href="https://occurrent.org"><img src="https://raw.githubusercontent.com/johanhaleby/occurrent/master/occurrent-logo-196x196.png" width="98" height="98" alt="Occurrent" title="Occurrent - Event Sourcing Utilities for the JVM"></img></a> | <a href="https://github.com/knative-sandbox/eventing-kafka-broker"><img src="https://cloudevents.io/img/logos/integrations/knative.png" height="98"></img></a> | <a href="https://www.http4k.org/guide/modules/cloud_events/"><img src="https://http4k.org/img/favicon-310.png" height="98" alt="http4k" title="http4k"></img></a> | |
## Community
@ -91,11 +99,25 @@ You can check out the examples in the [examples](examples) directory.
Each SDK may have its own unique processes, tooling and guidelines, common
governance related material can be found in the
[CloudEvents `community`](https://github.com/cloudevents/spec/tree/master/community)
[CloudEvents `community`](https://github.com/cloudevents/spec/tree/main/docs)
directory. In particular, in there you will find information concerning how SDK
projects are
[managed](https://github.com/cloudevents/spec/blob/master/community/SDK-GOVERNANCE.md),
[guidelines](https://github.com/cloudevents/spec/blob/master/community/SDK-maintainer-guidelines.md)
[managed](https://github.com/cloudevents/spec/blob/main/docs/SDK-GOVERNANCE.md),
[guidelines](https://github.com/cloudevents/spec/blob/main/docs/SDK-maintainer-guidelines.md)
for how PR reviews and approval, and our
[Code of Conduct](https://github.com/cloudevents/spec/blob/master/community/GOVERNANCE.md#additional-information)
[Code of Conduct](https://github.com/cloudevents/spec/blob/main/docs/GOVERNANCE.md#additional-information)
information.
If there is a security concern with one of the CloudEvents specifications, or
with one of the project's SDKs, please send an email to
[cncf-cloudevents-security@lists.cncf.io](mailto:cncf-cloudevents-security@lists.cncf.io).
## Additional SDK Resources
- [List of current active maintainers](MAINTAINERS.md)
- [How to contribute to the project](CONTRIBUTING.md)
- [SDK's License](LICENSE)
- [SDK's Release process](RELEASING.md)
- [SDK Maintainer's guide](MAINTAINERS_GUIDE.md)
[http4k]: https://www.http4k.org/guide/reference/cloud_events/

12
RELEASING.md Normal file
View File

@ -0,0 +1,12 @@
# Release Process
The release process is automated with Github actions. In order to perform a release:
1. Check if main CI pass.
1. Open the Github repository main page and go in the tab "Actions". Trigger the workflow "Bump version" and insert the new version to release. This will create a new release PR.
1. Check the release PR, merge it and cleanup the created branch.
1. Wait for the CI to complete the deploy of the modules to OSSRH.
1. Using the Github UI, create a new release, specifying the release notes and the tag to use.
1. Trigger again the workflow "Bump version" to bump versions back to a snapshot version.
1. Check the snapshot release PR, merge it and cleanup the created branch.

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-parent</artifactId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<artifactId>cloudevents-amqp-proton</artifactId>
@ -14,7 +14,7 @@
<packaging>jar</packaging>
<properties>
<protonj.version>0.33.7</protonj.version>
<protonj.version>0.34.1</protonj.version>
<jsr305.version>3.0.2</jsr305.version>
<module-name>io.cloudevents.amqp.proton</module-name>
</properties>

View File

@ -24,7 +24,7 @@
<parent>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-parent</artifactId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<artifactId>cloudevents-api</artifactId>

View File

@ -23,10 +23,10 @@ import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Set;
/**
* Materialized CloudEvent Extension interface to read/write the extension attributes key/values.
* Materialized CloudEvent extension interface to read/write the extension attributes key/values.
*/
@ParametersAreNonnullByDefault
public interface Extension {
public interface CloudEventExtension {
/**
* Fill this materialized extension with values from a {@link CloudEventExtensions} implementation.
@ -39,7 +39,7 @@ public interface Extension {
* Get the attribute of extension named {@code key}.
*
* @param key the name of the extension attribute
* @return the extension value in one of the valid types String/Number/Boolean
* @return the extension value in one of the valid types String/Number/Boolean/URI/OffsetDateTime/byte[]
* @throws IllegalArgumentException if the key is unknown to this extension
*/
@Nullable

View File

@ -22,6 +22,7 @@ import io.cloudevents.types.Time;
import javax.annotation.ParametersAreNonnullByDefault;
import java.net.URI;
import java.time.OffsetDateTime;
import java.util.Base64;
/**
* Interface to write the context attributes/extensions from a {@link io.cloudevents.rw.CloudEventContextReader} to a new representation.
@ -73,7 +74,25 @@ public interface CloudEventContextWriter {
}
/**
* Set attribute with type {@link URI}.
* Set attribute with type {@link Number}.
* This setter should not be invoked for specversion, because the writer should
* already know the specversion or because it doesn't need it to correctly write the value.
*
* @param name name of the attribute
* @param value value of the attribute
* @return self
* @throws CloudEventRWException if anything goes wrong while writing this extension.
* @throws IllegalArgumentException if you're trying to set the specversion attribute.
*
* @deprecated CloudEvent specification only permits {@link Integer} type as a
* numeric value.
*/
default CloudEventContextWriter withContextAttribute(String name, Number value) throws CloudEventRWException {
return withContextAttribute(name, value.toString());
}
/**
* Set attribute with type {@link Integer}.
* This setter should not be invoked for specversion, because the writer should
* already know the specversion or because it doesn't need it to correctly write the value.
*
@ -83,7 +102,7 @@ public interface CloudEventContextWriter {
* @throws CloudEventRWException if anything goes wrong while writing this extension.
* @throws IllegalArgumentException if you're trying to set the specversion attribute.
*/
default CloudEventContextWriter withContextAttribute(String name, Number value) throws CloudEventRWException {
default CloudEventContextWriter withContextAttribute(String name, Integer value) throws CloudEventRWException {
return withContextAttribute(name, value.toString());
}
@ -102,4 +121,18 @@ public interface CloudEventContextWriter {
return withContextAttribute(name, value.toString());
}
/**
* Set attribute with a binary type.
* This setter should not be invoked for specversion, because the writer should
* already know the specversion or because it doesn't need it to correctly write the value.
*
* @param name name of the attribute
* @param value value of the attribute
* @return self
* @throws CloudEventRWException if anything goes wrong while writing this extension.
* @throws IllegalArgumentException if you're trying to set the specversion attribute.
*/
default CloudEventContextWriter withContextAttribute(String name, byte[] value) throws CloudEventRWException {
return withContextAttribute(name, Base64.getEncoder().encodeToString(value));
}
}

View File

@ -137,6 +137,17 @@ public class CloudEventRWException extends RuntimeException {
);
}
public static CloudEventRWException newInvalidAttributeType(String attributeName,Object value){
return new CloudEventRWException(
CloudEventRWExceptionKind.INVALID_ATTRIBUTE_TYPE,
"Invalid attribute/extension type for \""
+ attributeName
+ "\": Type" + value.getClass().getCanonicalName()
+ ". Value: " + value
);
}
/**
* @param attributeName the invalid attribute name
* @param value the value of the attribute
@ -205,4 +216,15 @@ public class CloudEventRWException extends RuntimeException {
cause
);
}
/**
* An exception for use where none of the other variants are
* appropriate.
*
* @param msg A description error message.
* @return a new {@link CloudEventRWException}
*/
public static CloudEventRWException newOther(String msg){
return new CloudEventRWException(CloudEventRWExceptionKind.OTHER, msg);
}
}

View File

@ -32,7 +32,12 @@ public interface CloudEventReader {
/**
* Like {@link #read(CloudEventWriterFactory, CloudEventDataMapper)}, but with the identity {@link CloudEventDataMapper}.
*
* @param <W> The type of the {@link CloudEventWriter} created by writerFactory
* @param <R> The return value of the {@link CloudEventWriter} created by writerFactory
* @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event
* @see #read(CloudEventWriterFactory, CloudEventDataMapper)
* @return the value returned by {@link CloudEventWriter#end()} or {@link CloudEventWriter#end(CloudEventData)}
* @throws CloudEventRWException if something went wrong during the read.
*/
default <W extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<W, R> writerFactory) throws CloudEventRWException {
return read(writerFactory, CloudEventDataMapper.identity());

View File

@ -21,7 +21,7 @@
<parent>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-parent</artifactId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<artifactId>cloudevents-benchmarks</artifactId>
@ -59,6 +59,11 @@
<artifactId>cloudevents-kafka</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-sql</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
@ -136,7 +141,7 @@
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.1</version>
<version>3.1.3</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
@ -156,7 +161,7 @@
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>

View File

@ -0,0 +1,35 @@
package io.cloudevents.bench.sql;
import io.cloudevents.sql.Parser;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.infra.Blackhole;
public class CompileBenchmark {
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testCompileSmallExpression(Blackhole bh) {
bh.consume(
Parser.parseDefault("(a + b + c) = 10 AND TRUE OR CONCAT('1', '2', id) = '123'")
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testCompileSmallTrueConstantExpression(Blackhole bh) {
bh.consume(
Parser.parseDefault("(1 + 2 + 3) = 10 AND TRUE OR CONCAT('1', '2', '3') = 123")
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testCompileSmallFalseConstantExpression(Blackhole bh) {
bh.consume(
Parser.parseDefault("(1 + 2 + 3) = 10 AND FALSE OR CONCAT('1', '2', '3') = 124")
);
}
}

View File

@ -0,0 +1,92 @@
package io.cloudevents.bench.sql;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.sql.Expression;
import io.cloudevents.sql.Parser;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import static io.cloudevents.core.test.Data.V1_WITH_JSON_DATA_WITH_EXT;
public class RunBenchmark {
@State(Scope.Thread)
public static class TestCaseSmallExpression {
public CloudEvent event = CloudEventBuilder
.v1(V1_WITH_JSON_DATA_WITH_EXT)
.withExtension("a", "10")
.withExtension("b", 3)
.withExtension("c", "-3")
.build();
public Expression expression = Parser
.parseDefault("(a + b + c) = 10 AND TRUE OR CONCAT('1', '2', id) = '123'");
}
@State(Scope.Thread)
public static class TestCaseSmallTrueConstantExpression {
public CloudEvent event = CloudEventBuilder
.v1(V1_WITH_JSON_DATA_WITH_EXT)
.build();
public Expression expression = Parser
.parseDefault("(1 + 2 + 3) = 10 AND TRUE OR CONCAT('1', '2', '3') = 123");
}
@State(Scope.Thread)
public static class TestCaseSmallFalseConstantExpression {
public CloudEvent event = CloudEventBuilder
.v1(V1_WITH_JSON_DATA_WITH_EXT)
.build();
public Expression expression = Parser
.parseDefault("(1 + 2 + 3) = 10 AND FALSE OR CONCAT('1', '2', '3') = 124");
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testEvaluateSmallExpression(TestCaseSmallExpression testCase, Blackhole bh) {
bh.consume(
testCase.expression.evaluate(testCase.event)
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testTryEvaluateSmallExpression(TestCaseSmallExpression testCase, Blackhole bh) {
bh.consume(
testCase.expression.tryEvaluate(testCase.event)
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testEvaluateSmallTrueConstantExpression(TestCaseSmallTrueConstantExpression testCase, Blackhole bh) {
bh.consume(
testCase.expression.evaluate(testCase.event)
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testTryEvaluateSmallTrueConstantExpression(TestCaseSmallTrueConstantExpression testCase, Blackhole bh) {
bh.consume(
testCase.expression.tryEvaluate(testCase.event)
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testEvaluateSmallFalseConstantExpression(TestCaseSmallFalseConstantExpression testCase, Blackhole bh) {
bh.consume(
testCase.expression.evaluate(testCase.event)
);
}
@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
public void testTryEvaluateSmallFalseConstantExpression(TestCaseSmallFalseConstantExpression testCase, Blackhole bh) {
bh.consume(
testCase.expression.tryEvaluate(testCase.event)
);
}
}

91
bom/pom.xml Normal file
View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018-Present The CloudEvents Authors
~ <p>
~ 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
~ <p>
~ http://www.apache.org/licenses/LICENSE-2.0
~ <p>
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
</parent>
<artifactId>cloudevents-bom</artifactId>
<name>CloudEvents - Bill of Materials</name>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-json-jackson</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-protobuf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-amqp-proton</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-basic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-vertx</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-restful-ws</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-kafka</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-sql</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -22,7 +22,7 @@
<parent>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-parent</artifactId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<artifactId>cloudevents-core</artifactId>

View File

@ -141,6 +141,28 @@ public interface CloudEventBuilder extends CloudEventWriter<CloudEvent> {
*/
CloudEventBuilder withData(String dataContentType, URI dataSchema, CloudEventData data);
/**
* Remove the {@code datacontenttype}, {@code dataschema} and {@code data} from the event
*
* @return self
*/
CloudEventBuilder withoutData();
/**
* Remove the {@code dataschema} from the event
*
* @return self
*/
CloudEventBuilder withoutDataSchema();
/**
* Remove the {@code datacontenttype} from the event
*
* @return self
*/
CloudEventBuilder withoutDataContentType();
/**
* Set an extension with provided key and string value
*
@ -186,13 +208,22 @@ public interface CloudEventBuilder extends CloudEventWriter<CloudEvent> {
*/
CloudEventBuilder withExtension(@Nonnull String key, @Nonnull OffsetDateTime value);
/**
* Set an extension with provided key and binary value
*
* @param key key of the extension attribute
* @param value value of the extension attribute
* @return self
*/
CloudEventBuilder withExtension(@Nonnull String key, @Nonnull byte[] value);
/**
* Add to the builder all the extension key/values of the provided extension
*
* @param extension materialized extension to set in the builder
* @return self
*/
CloudEventBuilder withExtension(@Nonnull Extension extension);
CloudEventBuilder withExtension(@Nonnull CloudEventExtension extension);
/**
* Remove from the the builder the provided extension key, if any
@ -208,7 +239,7 @@ public interface CloudEventBuilder extends CloudEventWriter<CloudEvent> {
* @param extension materialized extension to remove from the builder
* @return self
*/
CloudEventBuilder withoutExtension(@Nonnull Extension extension);
CloudEventBuilder withoutExtension(@Nonnull CloudEventExtension extension);
/**
* Build the event
@ -300,9 +331,9 @@ public interface CloudEventBuilder extends CloudEventWriter<CloudEvent> {
static CloudEventBuilder fromContext(@Nonnull CloudEventContext context) {
switch (context.getSpecVersion()) {
case V1:
return new io.cloudevents.core.v1.CloudEventBuilder(context);
return new io.cloudevents.core.v1.CloudEventBuilder(context);
case V03:
return new io.cloudevents.core.v03.CloudEventBuilder(context);
return new io.cloudevents.core.v03.CloudEventBuilder(context);
}
throw new IllegalStateException(
"The provided spec version doesn't exist. Please make sure your io.cloudevents deps versions are aligned."

View File

@ -18,7 +18,7 @@
package io.cloudevents.core.extensions;
import io.cloudevents.CloudEventExtensions;
import io.cloudevents.Extension;
import io.cloudevents.CloudEventExtension;
import io.cloudevents.core.extensions.impl.ExtensionUtils;
import java.net.URI;
@ -31,7 +31,7 @@ import java.util.Set;
*
* @see <a href=https://github.com/cloudevents/spec/blob/v1.0/extensions/dataref.md>https://github.com/cloudevents/spec/blob/v1.0/extensions/dataref.md</a>
*/
public final class DatarefExtension implements Extension {
public final class DatarefExtension implements CloudEventExtension {
/**
* The key of the {@code dataref} extension

View File

@ -18,7 +18,7 @@
package io.cloudevents.core.extensions;
import io.cloudevents.CloudEventExtensions;
import io.cloudevents.Extension;
import io.cloudevents.CloudEventExtension;
import io.cloudevents.core.extensions.impl.ExtensionUtils;
import java.util.*;
@ -26,9 +26,9 @@ import java.util.*;
/**
* This extension embeds context from Distributed Tracing so that distributed systems can include traces that span an event-driven system.
*
* @see <a href="https://github.com/cloudevents/spec/blob/master/extensions/distributed-tracing.md">https://github.com/cloudevents/spec/blob/master/extensions/distributed-tracing.md</a>
* @see <a href="https://github.com/cloudevents/spec/blob/main/extensions/distributed-tracing.md">https://github.com/cloudevents/spec/blob/main/extensions/distributed-tracing.md</a>
*/
public final class DistributedTracingExtension implements Extension {
public final class DistributedTracingExtension implements CloudEventExtension {
/**
* The key of the {@code traceparent} extension

View File

@ -17,7 +17,7 @@
package io.cloudevents.core.extensions.impl;
import io.cloudevents.Extension;
import io.cloudevents.CloudEventExtension;
/**
* Collection of utilities to deal with materialized extensions
@ -28,11 +28,11 @@ public final class ExtensionUtils {
}
/**
* @param clazz the {@link Extension} class
* @param clazz the {@link CloudEventExtension} class
* @param key the invalid key
* @return an {@link IllegalArgumentException} when trying to access a key of the extension not existing.
*/
public static IllegalArgumentException generateInvalidKeyException(Class<? extends Extension> clazz, String key) {
public static IllegalArgumentException generateInvalidKeyException(Class<? extends CloudEventExtension> clazz, String key) {
return new IllegalArgumentException(clazz.getName() + " doesn't expect the attribute key \"" + key + "\"");
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2018-Present The CloudEvents Authors
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.core.format;
import io.cloudevents.CloudEvent;
import io.cloudevents.CloudEventData;
import io.cloudevents.rw.CloudEventDataMapper;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Collections;
import java.util.Set;
/**
* <p>A construct that aggregates a two-part identifier of file formats and format contents transmitted on the Internet.
*
* <p>The two parts of a {@code ContentType} are its <em>type</em> and a <em>subtype</em>; separated by a forward slash ({@code /}).
*
* <p>The constants enumerated by {@code ContentType} correspond <em>only</em> to the specialized formats supported by the Java SDK for CloudEvents.
*
* @see io.cloudevents.core.format.EventFormat
*/
@ParametersAreNonnullByDefault
public enum ContentType {
/**
* Content type associated with the JSON event format
*/
JSON("application/cloudevents+json"),
/**
* The content type for transports sending cloudevents in the protocol buffer format.
*/
PROTO("application/cloudevents+protobuf"),
/**
* The content type for transports sending cloudevents in the compact Avro format.
*/
AVRO_COMPACT("application/cloudevents+avrocompact"),
/**
* The content type for transports sending cloudevents in XML format.
*/
XML("application/cloudevents+xml");
private String value;
private ContentType(String value) { this.value = value; }
/**
* Return a string consisting of the slash-delimited ({@code /}) two-part identifier for this {@code enum} constant.
*/
public String value() { return value; }
/**
* Return a string consisting of the slash-delimited ({@code /}) two-part identifier for this {@code enum} constant.
*/
@Override
public String toString() { return value(); }
}

View File

@ -77,6 +77,8 @@ public abstract class BaseCloudEvent implements CloudEvent, CloudEventReader, Cl
writer.withContextAttribute(entry.getKey(), (URI) entry.getValue());
} else if (entry.getValue() instanceof OffsetDateTime) {
writer.withContextAttribute(entry.getKey(), (OffsetDateTime) entry.getValue());
} else if (entry.getValue() instanceof byte[]) {
writer.withContextAttribute(entry.getKey(), (byte[]) entry.getValue());
} else {
// This should never happen because we build that map only through our builders
throw new IllegalStateException("Illegal value inside extensions map: " + entry);

View File

@ -20,7 +20,7 @@ package io.cloudevents.core.impl;
import io.cloudevents.CloudEvent;
import io.cloudevents.CloudEventContext;
import io.cloudevents.CloudEventData;
import io.cloudevents.Extension;
import io.cloudevents.CloudEventExtension;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.core.data.BytesCloudEventData;
import io.cloudevents.rw.CloudEventRWException;
@ -98,6 +98,24 @@ public abstract class BaseCloudEventBuilder<SELF extends BaseCloudEventBuilder<S
return this.self;
}
@Override
public CloudEventBuilder withoutData() {
this.data = null;
return this.self;
}
@Override
public CloudEventBuilder withoutDataSchema() {
withDataSchema(null);
return this.self;
}
@Override
public CloudEventBuilder withoutDataContentType() {
withDataContentType(null);
return this.self;
}
public SELF withExtension(@Nonnull String key, @Nonnull String value) {
if (!isValidExtensionName(key)) {
throw CloudEventRWException.newInvalidExtensionName(key);
@ -106,6 +124,9 @@ public abstract class BaseCloudEventBuilder<SELF extends BaseCloudEventBuilder<S
return self;
}
// @TODO - I think this method should be removed/deprecated
// **Number** Is NOT a valid CE Context atrribute type.
public SELF withExtension(@Nonnull String key, @Nonnull Number value) {
if (!isValidExtensionName(key)) {
throw CloudEventRWException.newInvalidExtensionName(key);
@ -114,6 +135,14 @@ public abstract class BaseCloudEventBuilder<SELF extends BaseCloudEventBuilder<S
return self;
}
public SELF withExtension(@Nonnull String key, @Nonnull Integer value) {
if (!isValidExtensionName(key)) {
throw CloudEventRWException.newInvalidExtensionName(key);
}
this.extensions.put(key, value);
return self;
}
public SELF withExtension(@Nonnull String key, @Nonnull Boolean value) {
if (!isValidExtensionName(key)) {
throw CloudEventRWException.newInvalidExtensionName(key);
@ -140,6 +169,15 @@ public abstract class BaseCloudEventBuilder<SELF extends BaseCloudEventBuilder<S
return self;
}
@Override
public CloudEventBuilder withExtension(@Nonnull String key, @Nonnull byte[] value) {
if (!isValidExtensionName(key)) {
throw CloudEventRWException.newInvalidExtensionName(key);
}
this.extensions.put(key, value);
return self;
}
@Override
public SELF withoutExtension(@Nonnull String key) {
this.extensions.remove(key);
@ -147,12 +185,12 @@ public abstract class BaseCloudEventBuilder<SELF extends BaseCloudEventBuilder<S
}
@Override
public SELF withoutExtension(@Nonnull Extension extension) {
public SELF withoutExtension(@Nonnull CloudEventExtension extension) {
extension.getKeys().forEach(this::withoutExtension);
return self;
}
public SELF withExtension(@Nonnull Extension extension) {
public SELF withExtension(@Nonnull CloudEventExtension extension) {
for (String key : extension.getKeys()) {
Object value = extension.getValue(key);
if (value != null) {
@ -180,22 +218,24 @@ public abstract class BaseCloudEventBuilder<SELF extends BaseCloudEventBuilder<S
protected static IllegalStateException createMissingAttributeException(String attributeName) {
return new IllegalStateException("Attribute '" + attributeName + "' cannot be null");
}
protected static IllegalStateException createEmptyAttributeException(String attributeName) {
return new IllegalStateException("Attribute '" + attributeName + "' cannot be empty");
}
/**
* Validates the extension name as defined in CloudEvents spec.
*
* @param name the extension name
* @return true if extension name is valid, false otherwise
* @see <a href="https://github.com/cloudevents/spec/blob/master/spec.md#attribute-naming-convention">attribute-naming-convention</a>
* @see <a href="https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#naming-conventions">attribute-naming-conventions</a>
*/
private static boolean isValidExtensionName(String name) {
if(name.length() > 20){
return false;
}
char[] chars = name.toCharArray();
for (char c : chars)
if (!isValidChar(c)) {
for (int i = 0; i < name.length(); i++) {
if (!isValidChar(name.charAt(i))) {
return false;
}
}
return true;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2018-Present The CloudEvents Authors
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.core.impl;
import javax.annotation.Nonnull;
final public class StringUtils {
private StringUtils() {
// Prevent construction.
}
public static boolean startsWithIgnoreCase(@Nonnull final String s, @Nonnull final String prefix) {
return s.regionMatches(true /* ignoreCase */, 0, prefix, 0, prefix.length());
}
}

View File

@ -56,6 +56,9 @@ public abstract class BaseGenericBinaryMessageReaderImpl<HK, HV> extends BaseBin
// This implementation avoids to use visitAttributes and visitExtensions
// in order to complete the visit in one loop
this.forEachHeader((key, value) -> {
if (value == null) {
return;
}
if (isContentTypeHeader(key)) {
visitor.withContextAttribute(CloudEventV1.DATACONTENTTYPE, toCloudEventsValue(value));
} else if (isCloudEventsHeader(key)) {

View File

@ -59,6 +59,15 @@ public class MessageUtils {
EventFormat format = EventFormatProvider.getInstance().resolveFormat(ct);
if (format != null) {
return structuredMessageFactory.apply(format);
} else {
/**
* The format wasn't one we support, but if it's part of the
* CloudEvent family it indicates it's a structured
* representation that we can't interpret.
*/
if (ct.startsWith("application/cloudevents")) {
throw newUnknownEncodingException();
}
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2018-Present The CloudEvents Authors
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.core.provider;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.validator.CloudEventValidator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ServiceLoader;
/**
* CloudEventValidatorProvider is a singleton class which loads and access CE Validator service providers on behalf of service clients.
*/
public class CloudEventValidatorProvider {
private static final CloudEventValidatorProvider cloudEventValidatorProvider = new CloudEventValidatorProvider();
private final Collection<CloudEventValidator> validators;
private CloudEventValidatorProvider() {
final ServiceLoader<CloudEventValidator> loader = ServiceLoader.load(CloudEventValidator.class);
this.validators = new ArrayList<>(2);
for (CloudEventValidator cloudEventValidator : loader) {
validators.add(cloudEventValidator);
}
}
public static CloudEventValidatorProvider getInstance() {
return cloudEventValidatorProvider;
}
/**
* iterates through available Cloudevent validators.
*
* @param cloudEvent event to validate.
*/
public void validate(CloudEvent cloudEvent) {
for (final CloudEventValidator validator : validators) {
validator.validate(cloudEvent);
}
}
}

View File

@ -17,70 +17,96 @@
package io.cloudevents.core.provider;
import java.util.HashMap;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.StreamSupport;
import javax.annotation.ParametersAreNonnullByDefault;
import io.cloudevents.core.format.ContentType;
import io.cloudevents.core.format.EventFormat;
import io.cloudevents.lang.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.HashMap;
import java.util.ServiceLoader;
import java.util.stream.StreamSupport;
/**
* Singleton holding the discovered {@link EventFormat} implementations through {@link ServiceLoader}.
* Singleton holding the discovered {@link EventFormat} implementations through
* {@link ServiceLoader}.
* <p>
* You can resolve an event format using {@code EventFormatProvider.getInstance().resolveFormat(contentType)}.
* You can resolve an event format using
* {@code EventFormatProvider.getInstance().resolveFormat(contentType)}.
* <p>
* You can programmatically add a new {@link EventFormat} implementation using {@link #registerFormat(EventFormat)}.
* You can programmatically add a new {@link EventFormat} implementation using
* {@link #registerFormat(EventFormat)}.
*/
@ParametersAreNonnullByDefault
public final class EventFormatProvider {
private static class SingletonContainer {
private final static EventFormatProvider INSTANCE = new EventFormatProvider();
}
private static class SingletonContainer {
private final static EventFormatProvider INSTANCE = new EventFormatProvider();
}
/**
* @return instance of {@link EventFormatProvider}
*/
public static EventFormatProvider getInstance() {
return EventFormatProvider.SingletonContainer.INSTANCE;
}
/**
* @return instance of {@link EventFormatProvider}
*/
public static EventFormatProvider getInstance() {
return EventFormatProvider.SingletonContainer.INSTANCE;
}
private final HashMap<String, EventFormat> formats;
private final HashMap<String, EventFormat> formats;
private EventFormatProvider() {
this.formats = new HashMap<>();
private EventFormatProvider() {
this.formats = new HashMap<>();
StreamSupport.stream(
ServiceLoader.load(EventFormat.class).spliterator(),
false
).forEach(this::registerFormat);
}
StreamSupport.stream(ServiceLoader.load(EventFormat.class).spliterator(), false)
.forEach(this::registerFormat);
}
/**
* Register a new {@link EventFormat} programmatically.
*
* @param format the new format to register
*/
public void registerFormat(EventFormat format) {
for (String k : format.deserializableContentTypes()) {
this.formats.put(k, format);
}
}
/**
* Register a new {@link EventFormat} programmatically.
*
* @param format the new format to register
*/
public void registerFormat(EventFormat format) {
for (String k : format.deserializableContentTypes()) {
this.formats.put(k, format);
}
}
/**
* Resolve an event format starting from the content type.
*
* @param contentType the content type to resolve the event format
* @return null if no format was found for the provided content type
*/
@Nullable
public EventFormat resolveFormat(String contentType) {
int i = contentType.indexOf(';');
if (i != -1) {
contentType = contentType.substring(0, i);
}
return this.formats.get(contentType);
}
/**
* Enumerate the supported content types.
*
* @return an alphabetically sorted list of content types
*/
public Set<String> getContentTypes() {
Set<String> types = new TreeSet<>();
types.addAll(this.formats.keySet());
return types;
}
/**
* Resolve an event format starting from the content type.
*
* @param contentType the content type to resolve the event format
* @return null if no format was found for the provided content type
*/
@Nullable
public EventFormat resolveFormat(String contentType) {
int i = contentType.indexOf(';');
if (i != -1) {
contentType = contentType.substring(0, i);
}
return this.formats.get(contentType);
}
/**
* Resolve an event format starting from the content type.
*
* @param contentType the content type to resolve the event format
* @return null if no format was found for the provided content type
*/
@Nullable
public EventFormat resolveFormat(ContentType contentType) {
return this.formats.get(contentType.value());
}
}

View File

@ -18,7 +18,7 @@
package io.cloudevents.core.provider;
import io.cloudevents.CloudEventExtensions;
import io.cloudevents.Extension;
import io.cloudevents.CloudEventExtension;
import io.cloudevents.core.extensions.DatarefExtension;
import io.cloudevents.core.extensions.DistributedTracingExtension;
import io.cloudevents.lang.Nullable;
@ -30,7 +30,7 @@ import java.util.function.Supplier;
/**
* Singleton to materialize CloudEvent extensions as POJOs.
* <p>
* You can materialize an {@link Extension} POJO with {@code ExtensionProvider.getInstance().parseExtension(DistributedTracingExtension.class, event)}.
* You can materialize an {@link CloudEventExtension} POJO with {@code ExtensionProvider.getInstance().parseExtension(DistributedTracingExtension.class, event)}.
*/
@ParametersAreNonnullByDefault
public final class ExtensionProvider {
@ -59,10 +59,10 @@ public final class ExtensionProvider {
* Register a new extension type.
*
* @param <T> the type of the extension
* @param extensionClass the class implementing {@link Extension}
* @param extensionClass the class implementing {@link CloudEventExtension}
* @param factory the empty arguments factory
*/
public <T extends Extension> void registerExtension(Class<T> extensionClass, Supplier<T> factory) {
public <T extends CloudEventExtension> void registerExtension(Class<T> extensionClass, Supplier<T> factory) {
this.extensionFactories.put(extensionClass, factory);
}
@ -70,16 +70,16 @@ public final class ExtensionProvider {
* Parse an extension from the {@link CloudEventExtensions}, materializing the corresponding POJO.
*
* @param <T> the type of the extension
* @param extensionClass the class implementing {@link Extension}
* @param extensionClass the class implementing {@link CloudEventExtension}
* @param eventExtensions the event extensions to read
* @return the parsed extension
*/
@SuppressWarnings("unchecked")
@Nullable
public <T extends Extension> T parseExtension(Class<T> extensionClass, CloudEventExtensions eventExtensions) {
public <T extends CloudEventExtension> T parseExtension(Class<T> extensionClass, CloudEventExtensions eventExtensions) {
Supplier<?> factory = extensionFactories.get(extensionClass);
if (factory != null) {
Extension ext = (Extension) factory.get();
CloudEventExtension ext = (CloudEventExtension) factory.get();
ext.readFrom(eventExtensions);
return (T) ext;
}

View File

@ -16,9 +16,12 @@
*/
package io.cloudevents.core.v03;
import io.cloudevents.CloudEvent;
import io.cloudevents.SpecVersion;
import io.cloudevents.core.CloudEventUtils;
import io.cloudevents.core.impl.BaseCloudEventBuilder;
import io.cloudevents.core.provider.CloudEventValidatorProvider;
import io.cloudevents.core.v1.CloudEventV1;
import io.cloudevents.rw.CloudEventContextReader;
import io.cloudevents.rw.CloudEventContextWriter;
import io.cloudevents.rw.CloudEventRWException;
@ -121,8 +124,15 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
if (type == null) {
throw createMissingAttributeException("type");
}
if (subject != null && subject.isEmpty()) {
throw createEmptyAttributeException(("subject"));
}
return new CloudEventV03(id, source, type, time, schemaurl, datacontenttype, subject, this.data, this.extensions);
CloudEventV03 cloudEvent = new CloudEventV03(id, source, type, time, schemaurl, datacontenttype, subject, this.data, this.extensions);
final CloudEventValidatorProvider validator = CloudEventValidatorProvider.getInstance();
validator.validate(cloudEvent);
return cloudEvent;
}
@Override
@ -246,6 +256,26 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
}
}
@Override
public CloudEventContextWriter withContextAttribute(String name, Integer value) throws CloudEventRWException
{
requireValidAttributeWrite(name);
switch (name) {
case TIME:
case SCHEMAURL:
case ID:
case TYPE:
case DATACONTENTTYPE:
case DATACONTENTENCODING:
case SUBJECT:
case SOURCE:
throw CloudEventRWException.newInvalidAttributeType(name, Integer.class);
default:
withExtension(name, value);
return this;
}
}
@Override
public CloudEventContextWriter withContextAttribute(String name, Boolean value) throws CloudEventRWException {
requireValidAttributeWrite(name);
@ -264,4 +294,23 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
return this;
}
}
@Override
public CloudEventContextWriter withContextAttribute(String name, byte[] value) throws CloudEventRWException {
requireValidAttributeWrite(name);
switch (name) {
case TIME:
case SCHEMAURL:
case ID:
case TYPE:
case DATACONTENTTYPE:
case DATACONTENTENCODING:
case SUBJECT:
case SOURCE:
throw CloudEventRWException.newInvalidAttributeType(name, byte[].class);
default:
withExtension(name, value);
return this;
}
}
}

View File

@ -236,12 +236,12 @@ public final class CloudEventV03 extends BaseCloudEvent {
"id='" + id + '\'' +
", source=" + source +
", type='" + type + '\'' +
", datacontenttype='" + datacontenttype + '\'' +
", schemaurl=" + schemaurl +
", subject='" + subject + '\'' +
", time=" + time +
", data=" + getData() +
", extensions" + this.extensions +
((datacontenttype != null) ? ", datacontenttype='" + datacontenttype + '\'' : "") +
((schemaurl != null) ? ", schemaurl=" + schemaurl : "") +
((subject != null) ? ", subject='" + subject + '\'' : "") +
((time != null) ? ", time=" + time : "") +
((getData() != null) ? ", data=" + getData() : "") +
", extensions=" + this.extensions +
'}';
}
}

View File

@ -21,6 +21,8 @@ import io.cloudevents.CloudEvent;
import io.cloudevents.SpecVersion;
import io.cloudevents.core.CloudEventUtils;
import io.cloudevents.core.impl.BaseCloudEventBuilder;
import io.cloudevents.core.provider.CloudEventValidatorProvider;
import io.cloudevents.core.validator.CloudEventValidator;
import io.cloudevents.rw.CloudEventContextReader;
import io.cloudevents.rw.CloudEventContextWriter;
import io.cloudevents.rw.CloudEventRWException;
@ -118,8 +120,16 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
if (type == null) {
throw createMissingAttributeException(TYPE);
}
if (subject != null && subject.isEmpty()) {
throw createEmptyAttributeException(("subject"));
}
return new CloudEventV1(id, source, type, datacontenttype, dataschema, subject, time, this.data, this.extensions);
CloudEvent cloudEvent = new CloudEventV1(id, source, type, datacontenttype, dataschema, subject, time, this.data, this.extensions);
final CloudEventValidatorProvider validator = CloudEventValidatorProvider.getInstance();
validator.validate(cloudEvent);
return cloudEvent;
}
@Override
@ -238,6 +248,25 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
}
}
@Override
public CloudEventContextWriter withContextAttribute(String name, Integer value) throws CloudEventRWException
{
requireValidAttributeWrite(name);
switch (name) {
case TIME:
case DATASCHEMA:
case ID:
case TYPE:
case DATACONTENTTYPE:
case SUBJECT:
case SOURCE:
throw CloudEventRWException.newInvalidAttributeType(name, Integer.class);
default:
withExtension(name, value);
return this;
}
}
@Override
public CloudEventContextWriter withContextAttribute(String name, Boolean value) throws CloudEventRWException {
requireValidAttributeWrite(name);
@ -255,4 +284,23 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
return this;
}
}
@Override
public CloudEventContextWriter withContextAttribute(String name, byte[] value)
throws CloudEventRWException {
requireValidAttributeWrite(name);
switch (name) {
case TIME:
case DATASCHEMA:
case ID:
case TYPE:
case DATACONTENTTYPE:
case SUBJECT:
case SOURCE:
throw CloudEventRWException.newInvalidAttributeType(name, byte[].class);
default:
withExtension(name, value);
return this;
}
}
}

View File

@ -223,11 +223,11 @@ public final class CloudEventV1 extends BaseCloudEvent {
"id='" + id + '\'' +
", source=" + source +
", type='" + type + '\'' +
", datacontenttype='" + datacontenttype + '\'' +
", dataschema=" + dataschema +
", subject='" + subject + '\'' +
", time=" + time +
", data=" + getData() +
((datacontenttype != null) ? ", datacontenttype='" + datacontenttype + '\'' : "") +
((dataschema != null) ? ", dataschema=" + dataschema : "") +
((subject != null) ? ", subject='" + subject + '\'' : "") +
((time != null) ? ", time=" + time : "") +
((getData() != null) ? ", data=" + getData() : "") +
", extensions=" + this.extensions +
'}';
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2018-Present The CloudEvents Authors
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.core.validator;
import io.cloudevents.CloudEvent;
/**
* @author Vinay Bhat
* Interface which defines validation for CloudEvents attributes and extensions.
*/
public interface CloudEventValidator {
/**
* Validate the attributes of a CloudEvent.
*
* @param cloudEvent the CloudEvent to validate
*/
void validate(CloudEvent cloudEvent);
}

View File

@ -1,5 +1,7 @@
package io.cloudevents.core.data;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@ -8,7 +10,7 @@ class PojoCloudEventDataTest {
@Test
void testWrapAndMemoization() {
PojoCloudEventData<Integer> data = PojoCloudEventData.wrap(10, i -> i.toString().getBytes());
PojoCloudEventData<Integer> data = PojoCloudEventData.wrap(10, i -> i.toString().getBytes(StandardCharsets.UTF_8));
assertThat(data.getValue())
.isEqualTo(10);
@ -16,7 +18,7 @@ class PojoCloudEventDataTest {
byte[] firstConversion = data.toBytes();
assertThat(firstConversion)
.isEqualTo("10".getBytes());
.isEqualTo("10".getBytes(StandardCharsets.UTF_8));
assertThat(data.toBytes())
.isSameAs(firstConversion);
@ -24,7 +26,7 @@ class PojoCloudEventDataTest {
@Test
void testAlreadySerializedValue() {
byte[] serialized = "10".getBytes();
byte[] serialized = "10".getBytes(StandardCharsets.UTF_8);
PojoCloudEventData<Integer> data = PojoCloudEventData.wrap(10, v -> serialized);
assertThat(data.getValue())

View File

@ -1,15 +1,16 @@
package io.cloudevents.core.impl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.core.extensions.DistributedTracingExtension;
import io.cloudevents.core.test.Data;
import org.junit.jupiter.api.Test;
import java.util.Objects;
import static io.cloudevents.core.test.Data.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
public class BaseCloudEventBuilderTest {
@ -49,17 +50,23 @@ public class BaseCloudEventBuilderTest {
}
@Test
public void testLongExtensionName() {
Exception exception = assertThrows(RuntimeException.class, () -> {
CloudEvent cloudEvent = CloudEventBuilder.v1(Data.V1_WITH_JSON_DATA_WITH_EXT)
public void testLongExtensionNameV1() {
assertDoesNotThrow(() -> {
CloudEventBuilder.v1(Data.V1_WITH_JSON_DATA_WITH_EXT)
.withExtension("thisextensionnameistoolong", "")
.build();
});
String expectedMessage = "Invalid extensions name: thisextensionnameistoolong";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
}
@Test
public void testLongExtensionNameV03() {
assertDoesNotThrow(() -> {
CloudEventBuilder.v03(Data.V1_WITH_JSON_DATA_WITH_EXT)
.withExtension("thisextensionnameistoolong", "")
.build();
});
}
@Test
public void testInvalidExtensionName() {
Exception exception = assertThrows(RuntimeException.class, () -> {
@ -72,4 +79,64 @@ public class BaseCloudEventBuilderTest {
assertTrue(actualMessage.contains(expectedMessage));
}
@Test
public void testBinaryExtension() {
final String EXT_NAME = "verifyme";
CloudEvent given = CloudEventBuilder.v1(Data.V1_MIN)
.withExtension(EXT_NAME, Data.BINARY_VALUE)
.build();
// Sanity
assertNotNull(given);
// Did the extension stick
assertTrue(given.getExtensionNames().contains(EXT_NAME));
assertNotNull(given.getExtension(EXT_NAME));
// Does the extension have the right value
assertEquals(Data.BINARY_VALUE, given.getExtension(EXT_NAME));
}
@Test
public void withoutDataRemovesDataAttributeFromCopiedCloudEvent() {
CloudEvent original = CloudEventBuilder.v1(Data.V1_WITH_JSON_DATA_WITH_EXT).build();
CloudEvent copy = CloudEventBuilder.v1(original).withoutData().build();
assertAll(
() -> assertThat(copy.getData()).isNull(),
() -> assertThat(copy.getDataContentType()).isEqualTo(DATACONTENTTYPE_JSON),
() -> assertThat(copy.getDataSchema()).isEqualTo(DATASCHEMA)
);
}
@Test
public void withoutDataContentTypeRemovesDataContentTypeAttributeFromCopiedCloudEvent() {
CloudEvent original = CloudEventBuilder.v1(Data.V1_WITH_JSON_DATA_WITH_EXT).build();
CloudEvent copy = CloudEventBuilder.v1(original).withoutDataContentType().build();
assertAll(
() -> assertThat(Objects.requireNonNull(copy.getData()).toBytes()).isEqualTo(DATA_JSON_SERIALIZED),
() -> assertThat(copy.getDataContentType()).isNull(),
() -> assertThat(copy.getDataSchema()).isEqualTo(DATASCHEMA)
);
}
@Test
public void withoutDataSchemaRemovesDataSchemaAttributeFromCopiedCloudEvent() {
CloudEvent original = CloudEventBuilder.v1(Data.V1_WITH_JSON_DATA_WITH_EXT).build();
CloudEvent copy = CloudEventBuilder.v1(original).withoutDataSchema().build();
assertAll(
() -> assertThat(Objects.requireNonNull(copy.getData()).toBytes()).isEqualTo(DATA_JSON_SERIALIZED),
() -> assertThat(copy.getDataContentType()).isEqualTo(DATACONTENTTYPE_JSON),
() -> assertThat(copy.getDataSchema()).isNull()
);
}
}

View File

@ -91,4 +91,28 @@ public class CloudEventImplTest {
);
}
@Test
public void testToStringV1() {
CloudEvent event = CloudEventBuilder.v1()
.withId(ID)
.withType(TYPE)
.withSource(SOURCE)
.build();
assertThat(event.toString())
.doesNotContain("time");
}
@Test
public void testToStringV03() {
CloudEvent event = CloudEventBuilder.v03()
.withId(ID)
.withType(TYPE)
.withSource(SOURCE)
.build();
assertThat(event.toString())
.doesNotContain("time");
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2018-Present The CloudEvents Authors
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.core.impl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
public class StringUtilsTest {
@ParameterizedTest
@MethodSource("startsWithIgnoreCaseArgs")
public void startsWithIgnoreCase(final String s, final String prefix, final boolean expected) {
Assertions.assertThat(StringUtils.startsWithIgnoreCase(s, prefix)).isEqualTo(expected);
}
private static Stream<Arguments> startsWithIgnoreCaseArgs() {
return Stream.of(
Arguments.of("s", "s", true),
Arguments.of("sa", "S", true),
Arguments.of("saS", "As", false),
Arguments.of("sasso", "SASO", false),
Arguments.of("sasso", "SaSsO", true)
);
}
}

View File

@ -27,6 +27,25 @@ class MessageUtilsTest {
.isEqualTo(CloudEventRWException.CloudEventRWExceptionKind.UNKNOWN_ENCODING);
}
/**
* Verify an exception is thrown if an unsupported
* application/cloudevents content-type family is
* received.
*/
@ParameterizedTest
@MethodSource
void testBadContentTypes(String contentType) {
CloudEventRWException exception = assertThrows(CloudEventRWException.class, () ->
{
parseStructuredOrBinaryMessage(() -> contentType, eventFormat -> null, () -> "1.0", specVersion -> null);
});
assertThat(exception.getKind()).isEqualTo(CloudEventRWException.CloudEventRWExceptionKind.UNKNOWN_ENCODING);
}
@Test
void testParseStructuredOrBinaryMessage_StructuredMode() {
MessageUtils.parseStructuredOrBinaryMessage(() -> "application/cloudevents+csv;",
@ -54,4 +73,11 @@ class MessageUtilsTest {
);
}
private static Stream<Arguments> testBadContentTypes() {
return Stream.of(
Arguments.of("application/cloudevents"),
Arguments.of("application/cloudevents+morse")
);
}
}

View File

@ -55,7 +55,7 @@ public class CSVFormat implements EventFormat {
event.getData() != null
? new String(Base64.getEncoder().encode(event.getData().toBytes()), StandardCharsets.UTF_8)
: "null"
).getBytes();
).getBytes(StandardCharsets.UTF_8);
}
@Override
@ -70,7 +70,7 @@ public class CSVFormat implements EventFormat {
URI dataschema = splitted[5].equals("null") ? null : URI.create(splitted[5]);
String subject = splitted[6].equals("null") ? null : splitted[6];
OffsetDateTime time = splitted[7].equals("null") ? null : Time.parseTime(splitted[7]);
byte[] data = splitted[8].equals("null") ? null : Base64.getDecoder().decode(splitted[8].getBytes());
byte[] data = splitted[8].equals("null") ? null : Base64.getDecoder().decode(splitted[8].getBytes(StandardCharsets.UTF_8));
CloudEventBuilder builder = CloudEventBuilder.fromSpecVersion(sv)
.withId(id)

View File

@ -1,7 +1,7 @@
package io.cloudevents.core.mock;
import io.cloudevents.CloudEventData;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
public class MyCloudEventData implements CloudEventData {
@ -14,7 +14,7 @@ public class MyCloudEventData implements CloudEventData {
@Override
public byte[] toBytes() {
return Integer.toString(value).getBytes();
return Integer.toString(value).getBytes(StandardCharsets.UTF_8);
}
public int getValue() {

View File

@ -36,4 +36,9 @@ public class EventFormatProviderTest {
.isInstanceOf(CSVFormat.class);
}
@Test
void listTypes() {
assertThat(EventFormatProvider.getInstance().getContentTypes()).hasSize(1);
}
}

View File

@ -0,0 +1,17 @@
package io.cloudevents.core.test;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.validator.CloudEventValidator;
public class CloudEventCustomValidator implements CloudEventValidator {
@Override
public void validate(CloudEvent cloudEvent) {
String namespace = null;
if ((namespace = (String) cloudEvent.getExtension("namespace")) != null &&
!namespace.equals("sales")){
throw new IllegalStateException("Expecting sales in namespace extension");
}
}
}

View File

@ -21,7 +21,9 @@ import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.types.Time;
import java.math.BigDecimal;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.util.Objects;
import java.util.stream.Stream;
@ -38,9 +40,10 @@ public class Data {
public static final String SUBJECT = "sub";
public static final OffsetDateTime TIME = Time.parseTime("2018-04-26T14:48:09+02:00");
public static byte[] DATA_JSON_SERIALIZED = "{}".getBytes();
public static byte[] DATA_XML_SERIALIZED = "<stuff></stuff>".getBytes();
public static byte[] DATA_TEXT_SERIALIZED = "Hello World Lorena!".getBytes();
public static byte[] DATA_JSON_SERIALIZED = "{}".getBytes(StandardCharsets.UTF_8);
public static byte[] DATA_XML_SERIALIZED = "<stuff></stuff>".getBytes(StandardCharsets.UTF_8);
public static byte[] DATA_TEXT_SERIALIZED = "Hello World Lorena!".getBytes(StandardCharsets.UTF_8);
public static byte[] BINARY_VALUE = { (byte) 0xE0, (byte) 0xFF, (byte) 0x00, (byte) 0x44, (byte) 0xAA }; // Base64: 4P8ARKo=
public static final CloudEvent V1_MIN = CloudEventBuilder.v1()
.withId(ID)
@ -108,6 +111,23 @@ public class Data {
.withTime(TIME)
.build();
public static final CloudEvent V1_WITH_BINARY_EXT = CloudEventBuilder.v1()
.withId(ID)
.withType(TYPE)
.withSource(SOURCE)
.withExtension("binary", BINARY_VALUE)
.build();
public static final CloudEvent V1_WITH_NUMERIC_EXT = CloudEventBuilder.v1()
.withId(ID)
.withType(TYPE)
.withSource(SOURCE)
.withExtension("integer", 42)
.withExtension("decimal", new BigDecimal("42.42"))
.withExtension("float", 4.2f)
.withExtension("long", new Long(4200))
.build();
public static final CloudEvent V03_MIN = CloudEventBuilder.v03(V1_MIN).build();
public static final CloudEvent V03_WITH_JSON_DATA = CloudEventBuilder.v03(V1_WITH_JSON_DATA).build();
public static final CloudEvent V03_WITH_JSON_DATA_WITH_EXT = CloudEventBuilder.v03(V1_WITH_JSON_DATA_WITH_EXT).build();
@ -137,6 +157,18 @@ public class Data {
);
}
/**
* Due to the nature of CE there are scenarios where an event might be serialized
* in such a fashion that it can not be deserialized while retaining the orginal
* type information, this varies from format-2-format
*/
public static Stream<CloudEvent> v1NonRoundTripEvents() {
return Stream.of(
Data.V1_WITH_BINARY_EXT
);
}
public static Stream<CloudEvent> v03Events() {
return Stream.of(
Data.V03_MIN,

View File

@ -158,4 +158,27 @@ public class CloudEventBuilderTest {
).hasMessageContaining("Attribute 'type' cannot be null");
}
@Test
void testMissingSubject() {
CloudEvent actual = CloudEventBuilder
.v03()
.withId("000")
.withSource(URI.create("http://localhost"))
.withType(TYPE)
.build();
assertThat(actual).isNotNull();
}
@Test
void testEmptySubject() {
assertThatCode(() -> CloudEventBuilder
.v03()
.withId("000")
.withSource(URI.create("http://localhost"))
.withType(TYPE)
.withSubject("")
.build()
).hasMessageContaining("Attribute 'subject' cannot be empty");
}
}

View File

@ -142,4 +142,39 @@ public class CloudEventBuilderTest {
).hasMessageContaining("Attribute 'type' cannot be null");
}
@Test
void testValidatorProvider(){
assertThatCode(() -> CloudEventBuilder
.v1()
.withId("000")
.withSource(URI.create("http://localhost"))
.withType(TYPE)
.withExtension("namespace", "order")
.build()
).hasMessageContaining("Expecting sales in namespace extension");
}
@Test
void testMissingSubject() {
CloudEvent actual = CloudEventBuilder
.v1()
.withId("000")
.withSource(URI.create("http://localhost"))
.withType(TYPE)
.build();
assertThat(actual).isNotNull();
}
@Test
void testEmptySubject() {
assertThatCode(() -> CloudEventBuilder
.v1()
.withId("000")
.withSource(URI.create("http://localhost"))
.withType(TYPE)
.withSubject("")
.build()
).hasMessageContaining("Attribute 'subject' cannot be empty");
}
}

View File

@ -0,0 +1 @@
io.cloudevents.core.test.CloudEventCustomValidator

View File

@ -1,14 +1,14 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.3.4)
activesupport (6.0.6.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
coffee-script (2.4.1)
coffee-script-source
execjs
@ -16,7 +16,7 @@ GEM
colorator (1.1.0)
commonmarker (0.17.13)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.7)
concurrent-ruby (1.2.0)
dnsruby (1.61.5)
simpleidn (~> 0.1)
em-websocket (0.5.2)
@ -82,7 +82,7 @@ GEM
octokit (~> 4.0)
public_suffix (~> 3.0)
typhoeus (~> 1.3)
html-pipeline (2.14.0)
html-pipeline (2.14.3)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.6.0)
@ -203,30 +203,32 @@ GEM
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.3.0)
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.4.0)
mini_portile2 (2.8.8)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.2)
minitest (5.17.0)
multipart-post (2.1.1)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
nokogiri (1.18.3)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
octokit (4.19.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (3.1.1)
racc (1.8.1)
rake (13.0.1)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.4)
rexml (3.3.9)
rouge (3.23.0)
ruby-enum (0.8.0)
i18n
@ -248,13 +250,13 @@ GEM
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.8)
tzinfo (1.2.11)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
zeitwerk (2.4.1)
zeitwerk (2.6.6)
PLATFORMS
ruby

View File

@ -11,7 +11,7 @@ search_enabled: true
gh_edit_link: true
gh_edit_link_text: "Edit this page on GitHub."
gh_edit_repository: "https://github.com/cloudevents/sdk-java"
gh_edit_branch: "master"
gh_edit_branch: "main"
gh_edit_source: docs
gh_edit_view_mode: "tree"

View File

@ -18,7 +18,7 @@ binding for CloudEvents:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-amqp-proton</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -32,9 +32,7 @@ respectively. This module offers factory methods for creation of those in
public class ProtonAmqpMessageFactory {
public static MessageReader createReader(final Message message);
public static MessageReader createReader(final String contentType, final byte[] payload);
public static MessageReader createReader(final String contentType, final ApplicationProperties props, final byte[] payload);
public static MessageReader createReader(final String contentType, final ApplicationProperties props, @Nullable final Section body);
public static MessageWriter createWriter();
}
@ -45,5 +43,5 @@ public class ProtonAmqpMessageFactory {
The example uses the `vertx-proton` integration to send/receive CloudEvent
messages over AMQP:
- [Vertx AmqpServer](https://github.com/cloudevents/sdk-java/tree/master/examples/amqp-proton/src/main/java/io/cloudevents/examples/amqp/vertx/AmqpServer.java)
- [Vertx AmqpClient](https://github.com/cloudevents/sdk-java/tree/master/examples/amqp-proton/src/main/java/io/cloudevents/examples/amqp/vertx/AmqpClient.java)
- [Vertx AmqpServer](https://github.com/cloudevents/sdk-java/tree/main/examples/amqp-proton/src/main/java/io/cloudevents/examples/amqp/vertx/AmqpServer.java)
- [Vertx AmqpClient](https://github.com/cloudevents/sdk-java/tree/main/examples/amqp-proton/src/main/java/io/cloudevents/examples/amqp/vertx/AmqpClient.java)

View File

@ -17,7 +17,7 @@ For Maven based projects, use the following dependency:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-api</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -61,7 +61,5 @@ core module.
## Other interfaces
- `Extension` represents a _materialized_ in-memory representation of a
CloudEvent extension
- `SpecVersion` is an enum of CloudEvents' specification versions supported by
this SDK version.
- `CloudEventExtension` represents a _materialized_ in-memory representation of a CloudEvent extension
- `SpecVersion` is an enum of CloudEvents' specification versions supported by this SDK version.

49
docs/avro.md Normal file
View File

@ -0,0 +1,49 @@
---
title: CloudEvents Avro Compact
nav_order: 4
---
# CloudEvents Avro Compact
[![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-avro-compact.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-avro-compact)
This module provides the Avro Compact `EventFormat` implementation.
# Setup
For Maven based projects, use the following dependency:
```xml
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-avro-compact</artifactId>
<version>4.0.1</version>
</dependency>
```
No further configuration is required is use the module.
## Using the Avro Compact Event Format
### Event serialization
```java
import io.cloudevents.CloudEvent;
import io.cloudevents.core.provider.EventFormatProvider;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.avro.avro.compact.AvroCompactFormat;
CloudEvent event = CloudEventBuilder.v1()
.withId("hello")
.withType("example.vertx")
.withSource(URI.create("http://localhost"))
.build();
byte[] serialized = EventFormatProvider
.getInstance()
.resolveFormat(AvroCompactFormat.CONTENT_TYPE)
.serialize(event);
```
The `EventFormatProvider` will automatically resolve the format using the
`ServiceLoader` APIs.

View File

@ -16,7 +16,7 @@ For Maven based projects, use the following dependency:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-core</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -34,7 +34,7 @@ final CloudEvent event = CloudEventBuilder.v1()
.withId("000")
.withType("example.demo")
.withSource(URI.create("http://example.com"))
.withData("text/plain","Hello world!".getBytes())
.withData("text/plain","Hello world!".getBytes("UTF-8"))
.build();
```
@ -87,7 +87,7 @@ with Jackson, add `cloudevents-json-jackson` as a dependency and then using the
`EventFormatProvider`:
```java
import io.cloudevents.core.format.EventFormatProvider;
import io.cloudevents.core.provider.EventFormatProvider;
import io.cloudevents.jackson.JsonFormat;
EventFormat format = EventFormatProvider
@ -110,6 +110,6 @@ CloudEvent extensions can be materialized in their respective POJOs using the
import io.cloudevents.core.extensions.DistributedTracingExtension;
import io.cloudevents.core.provider.ExtensionProvider;
DistributedTracingExtension dte = ExtensionsParser.getInstance()
DistributedTracingExtension dte = ExtensionProvider.getInstance()
.parseExtension(DistributedTracingExtension.class, event);
```

View File

@ -27,7 +27,7 @@ HTTP Transport:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-basic</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -48,6 +48,6 @@ public class HttpMessageFactory {
## Examples
- [Standard Java HttpServer](https://github.com/cloudevents/sdk-java/tree/master/examples/basic-http/src/main/java/io/cloudevents/examples/http/basic/BasicHttpServer.java)
- [Http Client with HttpURLConnection](https://github.com/cloudevents/sdk-java/tree/master/examples/basic-http/src/main/java/io/cloudevents/examples/http/basic/HttpURLConnectionClient.java)
- [Http Servlet with Jetty](https://github.com/cloudevents/sdk-java/tree/master/examples/basic-http/src/main/java/io/cloudevents/examples/http/basic/JettyServer.java)
- [Standard Java HttpServer](https://github.com/cloudevents/sdk-java/tree/main/examples/basic-http/src/main/java/io/cloudevents/examples/http/basic/BasicHttpServer.java)
- [Http Client with HttpURLConnection](https://github.com/cloudevents/sdk-java/tree/main/examples/basic-http/src/main/java/io/cloudevents/examples/http/basic/HttpURLConnectionClient.java)
- [Http Servlet with Jetty](https://github.com/cloudevents/sdk-java/tree/main/examples/basic-http/src/main/java/io/cloudevents/examples/http/basic/JettyServer.java)

View File

@ -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
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-restful-ws-jakarta</artifactId>
<version>4.0.1</version>
</dependency>
```
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/main/examples/restful-ws-micropofile-liberty)

View File

@ -3,18 +3,18 @@ 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
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-restful-ws</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -118,5 +118,5 @@ public class CloudEventSender {
## Examples
- [Quarkus and Resteasy](https://github.com/cloudevents/sdk-java/tree/master/examples/restful-ws-quarkus)
- [Jersey and Spring Boot](https://github.com/cloudevents/sdk-java/tree/master/examples/restful-ws-spring-boot)
- [Quarkus and Resteasy](https://github.com/cloudevents/sdk-java/tree/main/examples/restful-ws-quarkus)
- [Jersey and Spring Boot](https://github.com/cloudevents/sdk-java/tree/main/examples/restful-ws-spring-boot)

View File

@ -14,7 +14,7 @@ HTTP Transport:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-vertx</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -95,4 +95,4 @@ public class CloudEventClientVerticle extends AbstractVerticle {
## Examples:
- [Vert.x Client and Server](https://github.com/cloudevents/sdk-java/tree/master/examples/vertx)
- [Vert.x Client and Server](https://github.com/cloudevents/sdk-java/tree/main/examples/vertx)

View File

@ -37,13 +37,20 @@ Using the Java SDK you can:
| - [Jakarta Restful WS](http-jakarta-restful-ws.md) | :heavy_check_mark: | :heavy_check_mark: |
| - [Basic](http-basic.md) | :heavy_check_mark: | :heavy_check_mark: |
| - [Spring](spring.md) | :heavy_check_mark: | :heavy_check_mark: |
| - [http4k][http4k]<sup></sup> | :heavy_check_mark: | :heavy_check_mark: |
| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
| - [Jackson](json-jackson.md) | :heavy_check_mark: | :heavy_check_mark: |
| Protobuf Event Format | :heavy_check_mark: | :heavy_check_mark: |
| - [Proto](protobuf.md) | :heavy_check_mark: | :heavy_check_mark: |
| XML Event Format | :heavy_check_mark: | :heavy_check_mark: |
| - [XML](xml.md) | :heavy_check_mark: | :heavy_check_mark: |
| [Kafka Protocol Binding](kafka.md) | :heavy_check_mark: | :heavy_check_mark: |
| MQTT Protocol Binding | :x: | :x: |
| NATS Protocol Binding | :x: | :x: |
| Web hook | :x: | :x: |
<sub>† Source/artifacts hosted externally</sub>
## Get Started
In order to start learning how to create, access and manipulate `CloudEvent`s,
@ -57,7 +64,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)
@ -67,7 +75,7 @@ and related interfaces, in order to interoperate with the other components of
the SDK, check out the [API module documentation](api.md).
You can also check out the
[**Examples**](https://github.com/cloudevents/sdk-java/tree/master/examples).
[**Examples**](https://github.com/cloudevents/sdk-java/tree/main/examples).
## Modules
@ -83,12 +91,20 @@ a different feature from the different sub specs of
[Event Formats](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format),
`MessageReader` /`MessageWriter` to implement
[Protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding)
- [`cloudevents-bom`] Module providing a
[bill of materials (BOM)](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms)
for easier integration of CloudEvents in other projects
- [`cloudevents-json-jackson`] Implementation of [JSON Event format] with
[Jackson](https://github.com/FasterXML/jackson)
- [`cloudevents-protobuf`] Implementation of [Protobuf Event format] using code generated
from the standard [protoc](https://github.com/protocolbuffers/protobuf) compiler.
- [`cloudevents-xml`] Implementation of the XML Event Format.
- [`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]
@ -101,15 +117,21 @@ You can look at the latest published artifacts on
[Maven Central](https://search.maven.org/search?q=g:io.cloudevents).
[JSON Event format]: https://github.com/cloudevents/spec/blob/v1.0/json-format.md
[Protobuf Event format]: https://github.com/cloudevents/spec/blob/v1.0.1/protobuf-format.md
[HTTP Protocol Binding]: https://github.com/cloudevents/spec/blob/v1.0/http-protocol-binding.md
[Kafka Protocol Binding]: https://github.com/cloudevents/spec/blob/v1.0/kafka-protocol-binding.md
[AMQP Protocol Binding]: https://github.com/cloudevents/spec/blob/v1.0/amqp-protocol-binding.md
[`cloudevents-api`]: https://github.com/cloudevents/sdk-java/tree/master/api
[`cloudevents-core`]: https://github.com/cloudevents/sdk-java/tree/master/core
[`cloudevents-json-jackson`]: https://github.com/cloudevents/sdk-java/tree/master/formats/json-jackson
[`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-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
[`cloudevents-api`]: https://github.com/cloudevents/sdk-java/tree/main/api
[`cloudevents-bom`]: https://github.com/cloudevents/sdk-java/tree/main/bom
[`cloudevents-core`]: https://github.com/cloudevents/sdk-java/tree/main/core
[`cloudevents-json-jackson`]: https://github.com/cloudevents/sdk-java/tree/main/formats/json-jackson
[`cloudevents-protobuf`]: https://github.com/cloudevents/sdk-java/tree/main/formats/protobuf
[`cloudevents-xml`]: https://github.com/cloudevents/sdk-java/tree/main/formats/xml
[`cloudevents-http-vertx`]: https://github.com/cloudevents/sdk-java/tree/main/http/vertx
[`cloudevents-http-basic`]: https://github.com/cloudevents/sdk-java/tree/main/http/basic
[`cloudevents-http-restful-ws`]: https://github.com/cloudevents/sdk-java/tree/main/http/restful-ws
[`cloudevents-http-restful-ws-jakarta`]: https://github.com/cloudevents/sdk-java/tree/main/http/restful-ws-jakarta
[`cloudevents-kafka`]: https://github.com/cloudevents/sdk-java/tree/main/kafka
[`cloudevents-amqp-proton`]: https://github.com/cloudevents/sdk-java/tree/main/amqp
[`cloudevents-spring`]: https://github.com/cloudevents/sdk-java/tree/main/spring
[http4k]: https://www.http4k.org/guide/modules/cloud_events/

View File

@ -17,7 +17,7 @@ For Maven based projects, use the following dependency:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-json-jackson</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -28,9 +28,9 @@ adding the dependency to your project:
```java
import io.cloudevents.CloudEvent;
import io.cloudevents.core.format.EventFormatProvider;
import io.cloudevents.core.format.ContentType;
import io.cloudevents.core.provider.EventFormatProvider;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.jackson.JsonFormat;
CloudEvent event = CloudEventBuilder.v1()
.withId("hello")
@ -40,7 +40,7 @@ CloudEvent event = CloudEventBuilder.v1()
byte[]serialized = EventFormatProvider
.getInstance()
.resolveFormat(JsonFormat.CONTENT_TYPE)
.resolveFormat(ContentType.JSON)
.serialize(event);
```

View File

@ -10,14 +10,14 @@ nav_order: 5
Implementation of Kafka Protocol Binding to send and receive CloudEvents.
For Maven based projects, use the following to configure the
[Kafka Protocol Binding](https://github.com/cloudevents/spec/blob/master/kafka-protocol-binding.md):
[Kafka Protocol Binding](https://github.com/cloudevents/spec/blob/main/kafka-protocol-binding.md):
```xml
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-kafka</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
@ -64,7 +64,7 @@ public class CloudEventProducer {
You can configure the Encoding and EventFormat to use to emit the event.
Check out the
[`CloudEventSerializer`](https://github.com/cloudevents/sdk-java/tree/master/kafka/src/main/java/io/cloudevents/kafka/CloudEventSerializer.java)
[`CloudEventSerializer`](https://github.com/cloudevents/sdk-java/tree/main/kafka/src/main/java/io/cloudevents/kafka/CloudEventSerializer.java)
javadoc for more info.
### Partition key extension
@ -81,7 +81,7 @@ producerProps.put(
When using in your producer, this interceptor will pick the `partitionkey`
extension from the event and will set it as record key, regardless of the input record key.
Check out the [`PartitionKeyExtensionInterceptor`](https://github.com/cloudevents/sdk-java/tree/master/kafka/src/main/java/io/cloudevents/kafka/PartitionKeyExtensionInterceptor.java)
Check out the [`PartitionKeyExtensionInterceptor`](https://github.com/cloudevents/sdk-java/tree/main/kafka/src/main/java/io/cloudevents/kafka/PartitionKeyExtensionInterceptor.java)
javadoc for more info.
## Consuming CloudEvents

96
docs/protobuf.md Normal file
View File

@ -0,0 +1,96 @@
---
title: CloudEvents Protocol Buffers
nav_order: 4
---
# CloudEvents Protocol Buffers
[![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-protobuf.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-protobuf)
This module provides the Protocol Buffer (protobuf) `EventFormat` implementation using the Java
Protobuf runtime and classes generated from the CloudEvents
[proto spec](https://github.com/cloudevents/spec/blob/v1.0.1/spec.proto).
# Setup
For Maven based projects, use the following dependency:
```xml
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-protobuf</artifactId>
<version>4.0.1</version>
</dependency>
```
No further configuration is required is use the module.
## Using the Protobuf Event Format
### Event serialization
```java
import io.cloudevents.CloudEvent;
import io.cloudevents.core.format.ContentType;
import io.cloudevents.core.provider.EventFormatProvider;
import io.cloudevents.core.builder.CloudEventBuilder;
CloudEvent event = CloudEventBuilder.v1()
.withId("hello")
.withType("example.vertx")
.withSource(URI.create("http://localhost"))
.build();
byte[]serialized = EventFormatProvider
.getInstance()
.resolveFormat(ContentType.PROTO)
.serialize(event);
```
The `EventFormatProvider` will automatically resolve the `ProtobufFormat` using the
`ServiceLoader` APIs.
## Passing Protobuf messages as CloudEvent data.
The `ProtoCloudEventData` capability provides a convenience mechanism to handle Protobuf message object data.
### Building
```java
// Build my business event message.
com.google.protobuf.Message myMessage = ..... ;
// Wrap the protobuf message as CloudEventData.
CloudEventData ceData = ProtoCloudEventData.wrap(myMessage);
// Build the CloudEvent
CloudEvent event = CloudEventBuilder.v1()
.withId("hello")
.withType("example.protodata")
.withSource(URI.create("http://localhost"))
.withData(ceData)
.build();
```
### Reading
If the `ProtobufFormat` is used to deserialize a CloudEvent that contains a protobuf message object as data you can use
the `ProtoCloudEventData` to access it as an 'Any' directly.
```java
// Deserialize the event.
CloudEvent myEvent = eventFormat.deserialize(raw);
// Get the Data
CloudEventData eventData = myEvent.getData();
if (ceData instanceOf ProtoCloudEventData) {
// Obtain the protobuf 'any'
Any anAny = ((ProtoCloudEventData) eventData).getAny();
...
}
```

View File

@ -8,7 +8,7 @@ nav_order: 5
[![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-spring.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-spring)
This module provides the integration of `CloudEvent` with different Spring APIs,
like MVC, WebFlux and Messaging
like MVC, WebFlux, RSocket and Messaging
For Maven based projects, use the following dependency:
@ -17,10 +17,12 @@ For Maven based projects, use the following dependency:
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-spring</artifactId>
<version>2.0.0.RC2</version>
<version>4.0.1</version>
</dependency>
```
plus whatever you need to support your use case (e.g. `spring-boot-starter-webflux` for reactive HTTP).
## Introduction
This module provides classes and interfaces that can be used by
@ -38,8 +40,166 @@ details).
## Examples
Check out the samples:
### Spring MVC
- [spring-reactive](https://github.com/cloudevents/sdk-java/tree/master/examples/spring-reactive)
There is a `CloudEventHttpMessageConverter` that you can register for Spring MVC:
```java
@Configuration
public static class CloudEventHandlerConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new CloudEventHttpMessageConverter());
}
}
```
With this in place you can write a `@RestController` with `CloudEvent` inputs or outputs, and the conversion will be handled by Spring. Example "echo" endpoint:
```java
@PostMapping("/echo")
public CloudEvent ce(@RequestBody CloudEvent event) {
return CloudEventBuilder.from(event)
.withId(UUID.randomUUID().toString())
.withSource(URI.create("https://spring.io/foos"))
.withType("io.spring.event.Foo")
.withData(event.getData().toBytes())
.build();
}
```
Both structured and binary events are supported. So if you know that the `CloudEvent` is in binary mode and the data can be converted to a `Foo`, then you can also use the `CloudEventHttpUtils` to deal with HTTP headers and stick to POJOs in the handler method. Example:
```java
@PostMapping("/echo")
public ResponseEntity<Foo> echo(@RequestBody Foo foo, @RequestHeader HttpHeaders headers) {
CloudEvent attributes = CloudEventHttpUtils.fromHttp(headers)
.withId(UUID.randomUUID().toString())
.withSource(URI.create("https://spring.io/foos"))
.withType("io.spring.event.Foo")
.build();
HttpHeaders outgoing = CloudEventHttpUtils.toHttp(attributes);
return ResponseEntity.ok().headers(outgoing).body(foo);
}
```
### Spring Webflux
If you are using Spring Webflux instead of Spring MVC you can use the same patterns, but the configuration is different. In this case we have a pair of readers and writers that you can register with the `CodecCustomizer`:
```java
@Configuration
public static class CloudEventHandlerConfiguration implements CodecCustomizer {
@Override
public void customize(CodecConfigurer configurer) {
configurer.customCodecs().register(new CloudEventHttpMessageReader());
configurer.customCodecs().register(new CloudEventHttpMessageWriter());
}
}
```
Then you can write similar code to the MVC example above, but with reactive signatures. Example echo endpoint:
```java
@PostMapping("/event")
public Mono<CloudEvent> event(@RequestBody Mono<CloudEvent> body) {
return body.map(event -> CloudEventBuilder.from(event)
.withId(UUID.randomUUID().toString())
.withSource(URI.create("https://spring.io/foos"))
.withType("io.spring.event.Foo")
.withData(event.getData().toBytes()).build());
}
```
The `CodecCustomizer` also works on the client side, so you can use it anywhere that you use a `WebClient` (including in an MVC application). Here's a simple example of a Cloud Event HTTP client:
```java
WebClient client = ...; // Either WebClient.create() or @Autowired a WebClient.Builder
CloudEvent event = ...; // Create a CloudEvent
Mono<CloudEvent> response = client.post()
.uri("http://localhost:8080/events")
.bodyValue(event)
.retrieve()
.bodyToMono(CloudEvent.class);
```
### Messaging
Spring Messaging is applicable in a wide range of use cases including WebSockets, JMS, Apache Kafka, RabbitMQ and others. It is also a core part of the Spring Cloud Function and Spring Cloud Stream libraries, so those are natural tools to use to build applications that use Cloud Events. The core abstraction in Spring is the `Message` which carries headers and a payload, just like a `CloudEvent`. Since the mapping is quite direct it makes sense to have a set of converters for Spring applications, so you can consume and produce `CloudEvents`, by treating them as `Messages`. This project provides a converter that you can register in a Spring Messaging application:
```java
@Configuration
public static class CloudEventMessageConverterConfiguration {
@Bean
public CloudEventMessageConverter cloudEventMessageConverter() {
return new CloudEventMessageConverter();
}
}
```
A simple echo with Spring Cloud Function could then be written as:
```java
@Bean
public Function<CloudEvent, CloudEvent> events() {
return event -> CloudEventBuilder.from(event)
.withId(UUID.randomUUID().toString())
.withSource(URI.create("https://spring.io/foos"))
.withType("io.spring.event.Foo")
.withData(event.getData().toBytes())
.build();
}
```
(If the application was a webapp with `spring-cloud-function-web` you would need the HTTP converters or codecs as well, per the example above.)
### Generic Encoder and Decoder
Some applications present Cloud Events as binary data, but do not have "headers" like in HTTP or messages. For those use cases there is a lower level construct in Spring, and this project provides implementations in the form of `CloudEventEncoder` and `CloudEventDecoder`. Since the headers are not available in the surrounding abstraction, these only support _structured_ Cloud Events, where the attributes and data are packed together in the same byte buffer. As an example in an RSockets application you can register them like this:
```java
@Bean
@Order(-1)
public RSocketStrategiesCustomizer cloudEventsCustomizer() {
return new RSocketStrategiesCustomizer() {
@Override
public void customize(Builder strategies) {
strategies.encoder(new CloudEventEncoder());
strategies.decoder(new CloudEventDecoder());
}
};
}
```
and then a simple echo endpoint could be written like this:
```java
@MessageMapping("event")
public Mono<CloudEvent> event(@RequestBody Mono<CloudEvent> body) {
return body.map(event -> CloudEventBuilder.from(event)
.withId(UUID.randomUUID().toString())
.withSource(URI.create("https://spring.io/foos"))
.withType("io.spring.event.Foo")
.withData(event.getData().toBytes())
.build());
}
```
### More
Check out the integration tests and samples:
- [spring-reactive](https://github.com/cloudevents/sdk-java/tree/main/examples/spring-reactive)
shows how to receive and send CloudEvents through HTTP using Spring Boot and
Webflux.
- [spring-rsocket](https://github.com/cloudevents/sdk-java/tree/main/examples/spring-rsocket)
shows how to receive and send CloudEvents through RSocket using Spring Boot.
- [spring-cloud-function](https://github.com/cloudevents/sdk-java/tree/main/examples/spring-function)
shows how to consume and process CloudEvents via Spring Cloud Function.

77
docs/xml.md Normal file
View File

@ -0,0 +1,77 @@
---
title: CloudEvents XML Format
nav_order: 4
---
# CloudEvents XML Format
[![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-xml.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-xml)
This module provides and `EventFormat` implementation that adheres
to the CloudEvent XML Format specification.
This format also supports specialized handling for XML CloudEvent `data`.
For Maven based projects, use the following dependency:
```xml
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-xml</artifactId>
<version>4.0.1</version>
</dependency>
```
## Using the XML Event Format
You don't need to perform any operation to configure the module, more than
adding the dependency to your project:
```java
import io.cloudevents.CloudEvent;
import io.cloudevents.core.format.ContentType;
import io.cloudevents.core.provider.EventFormatProvider;
import io.cloudevents.core.builder.CloudEventBuilder;
CloudEvent event = CloudEventBuilder.v1()
.withId("hello")
.withType("example.xml")
.withSource(URI.create("http://localhost"))
.build();
byte[] serialized = EventFormatProvider
.getInstance()
.resolveFormat(ContentType.XML)
.serialize(event);
```
The `EventFormatProvider` will resolve automatically the `XMLFormat` using the
`ServiceLoader` APIs.
XML Document data handling is supported via the `XMLCloudEventData`
facility. This convenience wrapper can be used with `any` other supported
format.
```java
import org.w3c.dom.Document;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.xml.XMLCloudEventData;
// Create the business event data.
Document xmlDoc = .... ;
// Wrap it into CloudEventData
CloudEventData myData = XMLCloudEventData.wrap(xmlDoc);
// Construct the event
CloudEvent event = CloudEventBuilder.v1()
.withId("hello")
.withType("example.xml")
.withSource(URI.create("http://localhost"))
.withData(myData)
.build();
```

View File

@ -3,14 +3,15 @@
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-amqp-proton-example</artifactId>
<properties>
<vertx.version>4.0.0.Beta1</vertx.version>
<module-name>cloudevents.example.amqp.proton</module-name>
<vertx.version>4.0.0.Beta1</vertx.version>
</properties>
<dependencies>
<dependency>

View File

@ -15,6 +15,7 @@ import org.apache.qpid.proton.message.Message;
import java.io.PrintWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
/**
* A example vertx-based AMQP client that interacts with a remote AMQP server to send and receive CloudEvent messages.
@ -71,7 +72,7 @@ public class AmqpClient {
.withSource(URI.create("http://127.0.0.1/amqp-client"))
.withType("com.example.sampletype1")
.withTime(Time.parseTime("2020-11-06T21:47:12.037467+00:00"))
.withData(payload.toString().getBytes())
.withData(payload.toString().getBytes(StandardCharsets.UTF_8))
.build();
final Message message = ProtonAmqpMessageFactory.createWriter().writeBinary(event);

View File

@ -2,6 +2,7 @@ package io.cloudevents.examples.amqp.vertx;
import java.io.PrintWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
@ -81,7 +82,7 @@ public class AmqpServer {
.withType("com.example.sampletype1")
.withSource(URI.create("http://127.0.0.1/amqp-server"))
.withTime(OffsetDateTime.now())
.withData("{\"temp\": 5}".getBytes())
.withData("{\"temp\": 5}".getBytes(StandardCharsets.UTF_8))
.build();
final Message message = writer.writeBinary(event);

View File

@ -21,11 +21,14 @@
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-basic-http-example</artifactId>
<properties>
<module-name>cloudevents.example.basic.http</module-name>
</properties>
<dependencies>
<dependency>
@ -41,7 +44,7 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.35.v20201120</version>
<version>9.4.55.v20240627</version>
</dependency>
</dependencies>
</project>

View File

@ -5,11 +5,14 @@
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-kafka-example</artifactId>
<properties>
<module-name>cloudevents.example.kafka</module-name>
</properties>
<dependencies>
<dependency>

View File

@ -12,6 +12,7 @@ import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.StringSerializer;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.UUID;
@ -33,7 +34,7 @@ public class SampleProducer {
// Configure the CloudEventSerializer to emit events as json structured events
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, CloudEventSerializer.class);
props.put(CloudEventSerializer.ENCODING_CONFIG, Encoding.BINARY);
props.put(CloudEventSerializer.ENCODING_CONFIG, Encoding.STRUCTURED);
props.put(CloudEventSerializer.EVENT_FORMAT_CONFIG, JsonFormat.CONTENT_TYPE);
// Create the KafkaProducer
@ -42,7 +43,7 @@ public class SampleProducer {
// Create an event template to set basic CloudEvent attributes
CloudEventBuilder eventTemplate = CloudEventBuilder.v1()
.withSource(URI.create("https://github.com/cloudevents/sdk-java/tree/master/examples/kafka"))
.withSource(URI.create("https://github.com/cloudevents/sdk-java/tree/main/examples/kafka"))
.withType("producer.example");
for (int i = 0; i < MESSAGE_COUNT; i++) {
@ -53,7 +54,7 @@ public class SampleProducer {
// Create the event starting from the template
CloudEvent event = eventTemplate.newBuilder()
.withId(id)
.withData("text/plain", data.getBytes())
.withData("text/plain", data.getBytes(StandardCharsets.UTF_8))
.build();
// Send the record

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>cloudevents-parent</artifactId>
<groupId>io.cloudevents</groupId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -21,11 +21,15 @@
<modules>
<module>kafka</module>
<module>restful-ws-quarkus</module>
<module>restful-ws-microprofile-liberty</module>
<module>vertx</module>
<module>basic-http</module>
<module>restful-ws-spring-boot</module>
<module>amqp-proton</module>
<module>spring-reactive</module>
<module>spring-rsocket</module>
<module>spring-function</module>
<module>rocketmq</module>
</modules>
</project>

View File

@ -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
```

View File

@ -0,0 +1,185 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>4.1.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-restful-ws-microprofile-liberty-example</artifactId>
<packaging>war</packaging>
<properties>
<openliberty.maven.version>3.5.1</openliberty.maven.version>
<app.name>cloudevents-microprofile</app.name>
<module-name>cloudevents.example.restful.ws.microprofile.liberty</module-name>
<!-- Liberty server properties -->
<final.name>cloudeventsServer</final.name>
<testServerHttpPort>9080</testServerHttpPort>
<testServerHttpsPort>9443</testServerHttpsPort>
<!--This is set in the ibm-web-ext.xml file -->
<warContext>cloudeventsexperiments</warContext>
<package.file>${project.build.directory}/${app.name}.zip</package.file>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<profiles>
<profile>
<id>runnable</id>
<properties>
<package.file>${project.build.directory}/${app.name}.jar</package.file>
<packaging.type>runnable</packaging.type>
</properties>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>5.0</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-restful-ws-jakarta</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.6.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>pom.xml</packagingExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-server-files</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeArtifactIds>server-snippet</includeArtifactIds>
<prependGroupId>true</prependGroupId>
<outputDirectory>
${project.build.directory}/wlp/usr/servers/${wlpServerName}/configDropins/defaults
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-app</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/wlp/usr/servers/${wlpServerName}/dropins
</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>${project.artifactId}-${project.version}.war</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- Enable liberty-maven plugin -->
<plugin>
<groupId>io.openliberty.tools</groupId>
<artifactId>liberty-maven-plugin</artifactId>
<version>${openliberty.maven.version}</version>
<executions>
<execution>
<id>package-server</id>
<phase>package</phase>
<goals>
<goal>create</goal>
<goal>install-feature</goal>
<goal>deploy</goal>
<goal>package</goal>
</goals>
<configuration>
<outputDirectory>target/wlp-package</outputDirectory>
</configuration>
</execution>
</executions>
<configuration>
<include>runnable</include>
<serverName>${final.name}</serverName>
<bootstrapProperties>
<project.name>${final.name}</project.name>
<jwt.issuer>https://server.example.com</jwt.issuer>
<app.context.root>/</app.context.root>
</bootstrapProperties>
</configuration>
</plugin>
<!-- Plugin to run functional tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
<executions>
<execution>
<phase>integration-test</phase>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<includes>
<include>**/it/**</include>
</includes>
<systemPropertyVariables>
<liberty.test.port>${testServerHttpPort}</liberty.test.port>
<war.name>${warContext}</war.name>
<running.bluemix>${running.bluemix}</running.bluemix>
<cf.context.root>${cf.context.root}</cf.context.root>
</systemPropertyVariables>
</configuration>
</execution>
<execution>
<id>verify-results</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<summaryFile>${project.build.directory}/test-reports/it/failsafe-summary.xml</summaryFile>
<reportsDirectory>${project.build.directory}/test-reports/it</reportsDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -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 {
}

View File

@ -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(StandardCharsets.UTF_8))
.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(StandardCharsets.UTF_8))
.withId("echo")
.withType("echo.http")
.withSource(URI.create("http://localhost"))
.build();
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<server description="${project.name}">
<featureManager>
<feature>microProfile-5.0</feature>
</featureManager>
<httpEndpoint id="defaultHttpEndpoint"
httpPort="9080"
httpsPort="9443"/>
<webApplication location="${project.name}.war">
<classloader apiTypeVisibility="+third-party" />
</webApplication>
<mpMetrics authentication="false"/>
<!-- This is the keystore that will be used by SSL and by JWT. -->
<keyStore id="defaultKeyStore" location="public.jks" type="JKS" password="atbash" />
<!-- The MP JWT configuration that injects the caller's JWT into a ResourceScoped bean for inspection. -->
<mpJwt id="jwtUserConsumer" keyName="theKeyId" audiences="targetService" issuer="${jwt.issuer}"/>
</server>

View File

@ -1,7 +1,11 @@
# Cloudevents Restful WS Quarkus example
This sample application has a `/users` REST endpoint in which you can manage the different users.
The way to create users is through CloudEvents. Here is an example POST:
The way to create users is through CloudEvents.
## Example requests
### [Binary Content mode](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/bindings/http-protocol-binding.md#31-binary-content-mode)
```shell script
curl -v http://localhost:8080/users \
@ -30,6 +34,29 @@ curl -v http://localhost:8080/users \
< Location: http://localhost:8080/users
```
### [Structured Content mode](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/bindings/http-protocol-binding.md#32-structured-content-mode)
```shell script
curl -v http://localhost:8080/users \
-H "Content-Type: application/cloudevents+json" \
-d @examples/user_structured.json
> POST /users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.82.0
> Accept: */*
> Content-Type: application/cloudevents+json
> Content-Length: 290
>
< HTTP/1.1 201 Created
< Location: http://localhost:8081/users
< content-length: 0
<
```
### Generated events
In order to also show how to create and send CloudEvents, generated events will be periodically sent
each 2 seconds through HTTP to the same endpoint using a REST client.

View File

@ -0,0 +1,13 @@
{
"specversion" : "1.0",
"type" : "User",
"source": "io.cloudevents.examples/user",
"id": "536808d3-88be-4077-9d7a-a3f162705f78",
"subject": "SUBJ-0001",
"data" : {
"username": "jsmith",
"firstName": "John",
"lastName": "Smith",
"age": 37
}
}

View File

@ -5,15 +5,16 @@
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-restful-ws-quarkus-example</artifactId>
<properties>
<quarkus-plugin.version>1.7.1.Final</quarkus-plugin.version>
<module-name>cloudevents.example.restful.ws.quarkus</module-name>
<quarkus-plugin.version>1.10.3.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.7.1.Final</quarkus.platform.version>
<quarkus.platform.version>1.10.3.Final</quarkus.platform.version>
</properties>
<dependencyManagement>
<dependencies>
@ -35,6 +36,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-scheduler</artifactId>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-api</artifactId>

View File

@ -1,18 +1,24 @@
package io.cloudevents.examples.quarkus.client;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import io.cloudevents.CloudEvent;
import io.cloudevents.jackson.JsonFormat;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@Path("/users")
@RegisterRestClient
public interface UserClient {
// This will emit binary encoded events.
// To use structured JSON encoding use @Consumes(JsonFormat.CONTENT_TYPE).
@POST
@Produces(MediaType.APPLICATION_JSON)
void emit(CloudEvent event);
void emitBinary(CloudEvent event);
@POST
@Consumes(JsonFormat.CONTENT_TYPE)
void emitStructured(CloudEvent event);
}

View File

@ -1,24 +1,24 @@
package io.cloudevents.examples.quarkus.client;
import java.net.URI;
import java.util.UUID;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.core.MediaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.cloudevents.CloudEvent;
import io.cloudevents.CloudEventData;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.core.data.PojoCloudEventData;
import io.cloudevents.examples.quarkus.model.User;
import io.quarkus.runtime.StartupEvent;
import io.smallrye.mutiny.Multi;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.ws.rs.core.MediaType;
import java.net.URI;
import java.time.Duration;
import java.util.UUID;
import io.quarkus.scheduler.Scheduled;
@ApplicationScoped
public class UserEventsGenerator {
@ -31,16 +31,19 @@ public class UserEventsGenerator {
@Inject
@RestClient
UserClient userClient;
long userCount=0;
public void init(@Observes StartupEvent startupEvent) {
Multi.createFrom().ticks().every(Duration.ofSeconds(2))
.onItem()
.transform(this::createEvent)
.subscribe()
.with(event -> {
LOGGER.info("try to emit user: {}", event.getId());
userClient.emit(event);
});
@Scheduled(every="2s")
public void init() {
CloudEvent event = createEvent(userCount++);
if(userCount % 2 == 0) {
LOGGER.info("try to emit binary event for user: {}", event.getId());
userClient.emitBinary(event);
} else {
LOGGER.info("try to emit structured event for user: {}", event.getId());
userClient.emitStructured(event);
}
}
private CloudEvent createEvent(long id) {

View File

@ -3,6 +3,7 @@ package io.cloudevents.examples.quarkus.resources;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cloudevents.CloudEvent;
import io.cloudevents.examples.quarkus.model.User;
import io.cloudevents.jackson.JsonFormat;
import io.cloudevents.jackson.PojoCloudEventDataMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -17,7 +18,7 @@ import java.util.HashMap;
import java.util.Map;
@Path("/users")
@Consumes(MediaType.APPLICATION_JSON)
@Consumes({MediaType.APPLICATION_JSON, JsonFormat.CONTENT_TYPE})
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {

View File

@ -3,4 +3,5 @@
## The Rest client will send events to the local UserResource
io.cloudevents.examples.quarkus.client.UserClient/mp-rest/url=http://localhost:8080
%test.io.cloudevents.examples.quarkus.client.UserClient/mp-rest/url=http://localhost:8081
io.cloudevents.examples.quarkus.client.UserClient/mp-rest/scope=javax.inject.Singleton

View File

@ -4,7 +4,6 @@ import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class UserResourceTest {

View File

@ -11,11 +11,11 @@ mvn spring-boot:run
You can try sending a request using `curl`:
```shell
curl -X POST -v -d '{"username": "slinkydeveloper", "firstName": "Francesco", "lastName": "Guardiani", "age": 23}' \ ~
-H'Content-type: application/json' \
-H'Ce-id: 1' \
-H'Ce-source: cloud-event-example' \
-H'Ce-type: happybirthday.myapplication' \
-H'Ce-specversion: 1.0' \
curl -X POST -v -d '{"username": "slinkydeveloper", "firstName": "Francesco", "lastName": "Guardiani", "age": 23}' \
-H 'Content-type: application/json' \
-H 'Ce-id: 1' \
-H 'Ce-source: cloud-event-example' \
-H 'Ce-type: happybirthday.myapplication' \
-H 'Ce-specversion: 1.0' \
http://localhost:8080/happy_birthday
```

View File

@ -5,15 +5,16 @@
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>2.0.0.RC2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-spring-boot-example</artifactId>
<properties>
<module-name>cloudevents.example.spring.boot</module-name>
<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring.version>5.2.8.RELEASE</spring.version>
<spring.version>5.2.9.RELEASE</spring.version>
</properties>
<dependencyManagement>

View File

@ -0,0 +1,27 @@
# RocketMQ + CloudEvents Sample
This example demonstrates the integration of [RocketMQ 5.x client library](https://github.com/apache/rocketmq-clients)
with CloudEvents to create a RocketMQ binding.
## Building the Project
```shell
mvn package
```
## Setting Up a RocketMQ Instance
Follow the [quickstart guide](https://rocketmq.apache.org/docs/quick-start/01quickstart) on the official RocketMQ
website to set up the necessary components, including nameserver, proxy, and broker.
## Event Production
```shell
mvn exec:java -Dexec.mainClass="io.cloudevents.examples.rocketmq.RocketmqProducer" -Dexec.args="foobar:8081 sample-topic"
```
## Event Consumption
```shell
mvn exec:java -Dexec.mainClass="io.cloudevents.examples.rocketmq.RocketmqConsumer" -Dexec.args="foobar:8081 sample-topic sample-consumer-group"
```

24
examples/rocketmq/pom.xml Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-rocketmq-example</artifactId>
<properties>
<module-name>cloudevents.example.rocketmq</module-name>
</properties>
<dependencies>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-rocketmq</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,50 @@
package io.cloudevents.examples.rocketmq;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.message.MessageReader;
import io.cloudevents.rocketmq.RocketMqMessageFactory;
import java.io.IOException;
import java.util.Collections;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.consumer.ConsumeResult;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.PushConsumer;
public class RocketmqConsumer {
private RocketmqConsumer() {
}
public static void main(String[] args) throws InterruptedException, ClientException, IOException {
if (args.length < 3) {
System.out.println("Usage: rocketmq_consumer <endpoints> <topic> <consumer_group>");
return;
}
final ClientServiceProvider provider = ClientServiceProvider.loadService();
String endpoints = args[0];
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
.build();
FilterExpression filterExpression = new FilterExpression();
String topic = args[1];
String consumerGroup = args[2];
// Create the RocketMQ Consumer.
PushConsumer pushConsumer = provider.newPushConsumerBuilder()
.setClientConfiguration(clientConfiguration)
.setConsumerGroup(consumerGroup)
.setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
.setMessageListener(messageView -> {
final MessageReader reader = RocketMqMessageFactory.createReader(messageView);
final CloudEvent event = reader.toEvent();
System.out.println("Received event=" + event + ", messageId=" + messageView.getMessageId());
return ConsumeResult.SUCCESS;
})
.build();
// Block the main thread, no need for production environment.
Thread.sleep(Long.MAX_VALUE);
// Close the push consumer when you don't need it anymore.
pushConsumer.close();
}
}

View File

@ -0,0 +1,64 @@
package io.cloudevents.examples.rocketmq;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.v1.CloudEventBuilder;
import io.cloudevents.rocketmq.RocketMqMessageFactory;
import io.cloudevents.types.Time;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;
import org.apache.rocketmq.shaded.com.google.gson.Gson;
public class RocketmqProducer {
private RocketmqProducer() {
}
public static void main(String[] args) throws ClientException, IOException {
if (args.length < 2) {
System.out.println("Usage: rocketmq_producer <endpoints> <topic>");
return;
}
final ClientServiceProvider provider = ClientServiceProvider.loadService();
String endpoints = args[0];
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
.build();
String topic = args[1];
// Create the RocketMQ Producer.
final Producer producer = provider.newProducerBuilder()
.setClientConfiguration(clientConfiguration)
.setTopics(topic)
.build();
final Gson gson = new Gson();
Map<String, String> payload = new HashMap<>();
payload.put("foo", "bar");
final CloudEvent event = new CloudEventBuilder()
.withId("client-id")
.withSource(URI.create("http://127.0.0.1/rocketmq-client"))
.withType("com.foobar")
.withTime(Time.parseTime("2022-11-09T21:47:12.032198+00:00"))
.withData(gson.toJson(payload).getBytes(StandardCharsets.UTF_8))
.build();
// Transform event into message.
final Message message = RocketMqMessageFactory.createWriter(topic).writeBinary(event);
try {
// Send the message.
final SendReceipt sendReceipt = producer.send(message);
System.out.println("Send message successfully, messageId=" + sendReceipt.getMessageId());
} catch (Exception e) {
System.out.println("Failed to send message");
e.printStackTrace();
}
// Close the producer when you don't need it anymore.
producer.close();
}
}

View File

@ -0,0 +1,75 @@
# Spring Reactive + CloudEvents sample
## Build
```shell
mvn package
```
## Start HTTP Server
```shell
mvn spring-boot:run
```
You can try sending a request using curl, and it echos back a cloud event the same body and with new `ce-*` headers:
```shell
curl -v -d '{"value": "Foo"}' \
-H'Content-type: application/json' \
-H'ce-id: 1' \
-H'ce-source: cloud-event-example' \
-H'ce-type: my.application.Foo' \
-H'ce-specversion: 1.0' \
http://localhost:8080/event
```
It also accepts data in "structured" format:
```shell
curl -v -H'Content-type: application/cloudevents+json' \
-d '{"data": {"value": "Foo"},
"id": "1",
"source": "cloud-event-example",
"type": "my.application.Foo",
"specversion": "1.0"}' \
http://localhost:8080/event
```
The `/event endpoint is implemented like this (the request and response are modelled directly as a `CloudEvent`):
```java
@PostMapping("/event")
public Mono<CloudEvent> event(@RequestBody Mono<CloudEvent> body) {
return ...;
}
```
and to make that work we need to install the codecs:
```java
@Configuration
public static class CloudEventHandlerConfiguration implements CodecCustomizer {
@Override
public void customize(CodecConfigurer configurer) {
configurer.customCodecs().register(new CloudEventHttpMessageReader());
configurer.customCodecs().register(new CloudEventHttpMessageWriter());
}
}
```
The same feature in Spring MVC is provided by the `CloudEventHttpMessageConverter`.
The `/foos` endpoint does the same thing. It doesn't use the `CloudEvent` data type directly, but instead models the request and response body as a `Foo` (POJO type):
```java
@PostMapping("/foos")
public ResponseEntity<Foo> echo(@RequestBody Foo foo, @RequestHeader HttpHeaders headers) {
...
}
```
Note that this endpoint only accepts "binary" format cloud events (context in HTTP headers like in the first example above). It translates the `HttpHeaders` to `CloudEventContext` using a utility class provided by `cloudevents-spring`.

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloudevents-examples</artifactId>
<groupId>io.cloudevents</groupId>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudevents-spring-function-example</artifactId>
<properties>
<module-name>cloudevents.example.spring.function</module-name>
<spring-boot.version>2.4.3</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-http-basic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.cloudevents</groupId>
<artifactId>cloudevents-json-jackson</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,64 @@
package io.cloudevents.examples.spring;
import java.net.URI;
import java.util.UUID;
import java.util.function.Function;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.CodecConfigurer;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.spring.messaging.CloudEventMessageConverter;
import io.cloudevents.spring.webflux.CloudEventHttpMessageReader;
import io.cloudevents.spring.webflux.CloudEventHttpMessageWriter;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public Function<CloudEvent, CloudEvent> events() {
return event -> CloudEventBuilder.from(event)
.withId(UUID.randomUUID().toString())
.withSource(URI.create("https://spring.io/foos"))
.withType("io.spring.event.Foo")
.withData(event.getData().toBytes())
.build();
}
/**
* Configure a MessageConverter for Spring Cloud Function to pick up and use to
* convert to and from CloudEvent and Message.
*/
@Configuration
public static class CloudEventMessageConverterConfiguration {
@Bean
public CloudEventMessageConverter cloudEventMessageConverter() {
return new CloudEventMessageConverter();
}
}
/**
* Configure an HTTP reader and writer so that we can process CloudEvents over
* HTTP via Spring Webflux.
*/
@Configuration
public static class CloudEventHandlerConfiguration implements CodecCustomizer {
@Override
public void customize(CodecConfigurer configurer) {
configurer.customCodecs().register(new CloudEventHttpMessageReader());
configurer.customCodecs().register(new CloudEventHttpMessageWriter());
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2019-2019 the original author or 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
*
* 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.
*/
package io.cloudevents.examples.spring;
class Foo {
private String value;
public Foo() {
}
public Foo(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "Foo [value=" + this.value + "]";
}
}

View File

@ -0,0 +1,112 @@
package io.cloudevents.examples.spring;
import java.net.URI;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {
@Autowired
private TestRestTemplate rest;
@LocalServerPort
private int port;
@Test
void echoWithCorrectHeaders() {
ResponseEntity<String> response = rest
.exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/foos")) //
.header("ce-id", "12345") //
.header("ce-specversion", "1.0") //
.header("ce-type", "io.spring.event") //
.header("ce-source", "https://spring.io/events") //
.contentType(MediaType.APPLICATION_JSON) //
.body("{\"value\":\"Dave\"}"), String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}");
HttpHeaders headers = response.getHeaders();
assertThat(headers).containsKey("ce-id");
assertThat(headers).containsKey("ce-source");
assertThat(headers).containsKey("ce-type");
assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345");
assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo");
assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos");
}
@Test
void structuredRequestResponseEvents() {
ResponseEntity<String> response = rest
.exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) //
.contentType(new MediaType("application", "cloudevents+json")) //
.body("{" //
+ "\"id\":\"12345\"," //
+ "\"specversion\":\"1.0\"," //
+ "\"type\":\"io.spring.event\"," //
+ "\"source\":\"https://spring.io/events\"," //
+ "\"data\":{\"value\":\"Dave\"}}"),
String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}");
HttpHeaders headers = response.getHeaders();
assertThat(headers).containsKey("ce-id");
assertThat(headers).containsKey("ce-source");
assertThat(headers).containsKey("ce-type");
assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345");
assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo");
assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos");
}
@Test
void requestResponseEvents() {
ResponseEntity<String> response = rest
.exchange(RequestEntity.post(URI.create("http://localhost:" + port + "/event")) //
.header("ce-id", "12345") //
.header("ce-specversion", "1.0") //
.header("ce-type", "io.spring.event") //
.header("ce-source", "https://spring.io/events") //
.contentType(MediaType.APPLICATION_JSON) //
.body("{\"value\":\"Dave\"}"), String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("{\"value\":\"Dave\"}");
HttpHeaders headers = response.getHeaders();
assertThat(headers).containsKey("ce-id");
assertThat(headers).containsKey("ce-source");
assertThat(headers).containsKey("ce-type");
assertThat(headers.getFirst("ce-id")).isNotEqualTo("12345");
assertThat(headers.getFirst("ce-type")).isEqualTo("io.spring.event.Foo");
assertThat(headers.getFirst("ce-source")).isEqualTo("https://spring.io/foos");
}
}

View File

@ -29,10 +29,10 @@ It also accepts data in "structured" format:
```shell
curl -v -H'Content-type: application/cloudevents+json' \
-d '{"data": {"value": "Foo"},
"ce-id: 1,
"ce-source": "cloud-event-example"
"ce-type": "my.application.Foo"
"ce-specversion": "1.0"}' \
"id: 1,
"source": "cloud-event-example"
"type": "my.application.Foo"
"specversion": "1.0"}' \
http://localhost:8080/event
```
@ -72,4 +72,4 @@ public ResponseEntity<Foo> echo(@RequestBody Foo foo, @RequestHeader HttpHeaders
}
```
Note that this endpoint only accepts "binary" format cloud events (context in HTTP headers like in the first example above). It translates the `HttpHeaders` to `CloudEventContext` using a utility class provided by `cloudevents-spring`.
Note that this endpoint only accepts "binary" format cloud events (context in HTTP headers like in the first example above). It translates the `HttpHeaders` to `CloudEventContext` using a utility class provided by `cloudevents-spring`.

Some files were not shown because too many files have changed in this diff Show More