diff --git a/docs/src/main/asciidoc/images/dev-ui-infinispan.png b/docs/src/main/asciidoc/images/dev-ui-infinispan.png
new file mode 100644
index 00000000000000..378347e23c317b
Binary files /dev/null and b/docs/src/main/asciidoc/images/dev-ui-infinispan.png differ
diff --git a/docs/src/main/asciidoc/images/infinispan-console-client-guide.png b/docs/src/main/asciidoc/images/infinispan-console-client-guide.png
new file mode 100644
index 00000000000000..b4ed55833898b0
Binary files /dev/null and b/docs/src/main/asciidoc/images/infinispan-console-client-guide.png differ
diff --git a/docs/src/main/asciidoc/infinispan-client-reference.adoc b/docs/src/main/asciidoc/infinispan-client-reference.adoc
new file mode 100644
index 00000000000000..285b9041d55ea2
--- /dev/null
+++ b/docs/src/main/asciidoc/infinispan-client-reference.adoc
@@ -0,0 +1,755 @@
+////
+This guide is maintained in the main Quarkus repository
+and pull requests should be submitted there:
+https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
+////
+= Infinispan Client Extension Reference Guide
+include::_attributes.adoc[]
+:categories: data
+:summary: Infinispan is an in memory distributed data store and cache server that offers flexible deployment options and robust capabilities for storing, managing, and processing data.
+
+Infinispan is a distributed, in-memory key/value store that provides Quarkus applications with a highly configurable
+and independently scalable data layer.
+This extension gives you client functionality that connects applications running on Quarkus with remote Infinispan clusters.
+
+To find out more about Infinispan, visit the https://infinispan.org/documentation[Infinispan documentation].
+
+== Solution
+
+We recommend that you complete each step in the following sections to create the application.
+However, you can proceed directly to the completed solution as follows:
+
+Clone the Git repository: `git clone {quickstarts-clone-url}` or download an {quickstarts-archive-url}[archive].
+Locate the solution in the `infinispan-client-quickstart` {quickstarts-tree-url}/infinispan-client-quickstart[directory].
+
+== Adding the Infinispan client extension
+
+Run the following command in the base directory of your Quarkus project to add the `infinispan-client` extension:
+
+:add-extension-extensions: infinispan-client
+include::{includes}/devtools/extension-add.adoc[]
+
+This command adds the following dependency to your build file:
+
+[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
+.pom.xml
+----
+
+ io.quarkus
+ quarkus-infinispan-client
+
+----
+
+[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
+.build.gradle
+----
+implementation 'io.quarkus:quarkus-infinispan-client'
+annotationProcessor 'org.infinispan.protostream:protostream-processor:4.6.1.Final' <1>
+----
+<1> Mandatory in the Gradle build to enable the generation of the files in the annotation based serialization
+
+== Configuring the Infinispan client
+
+Open the `application.properties` file in the `src/main/resources` directory with any text editor.
+
+Note that Infinispan documentation refers to a `hotrod-client.properties` file.
+You can configure the Infinispan client with either properties file but `application.properties` always takes
+priority over `hotrod-client.properties`.
+
+Additionally, you cannot update configuration properties at runtime.
+If you modify `application.properties` or `hotrod-client.properties`, you must rebuild the application before those changes take effect.
+
+== Connecting to Infinispan clusters
+
+If you are running an Infinispan Server add the following properties to connect:
+
+[source,properties]
+----
+quarkus.infinispan-client.hosts=localhost:11222 <1>
+
+quarkus.infinispan-client.username=admin <2>
+quarkus.infinispan-client.password=password <3>
+
+quarkus.infinispan-client.client-intelligence=BASIC <4>
+----
+<1> Sets Infinispan Server address list, separated with commas
+<2> Sets the authentication username
+<3> Sets the authentication password
+<4> Sets the client intelligence. Use BASIC as a workaround if using Docker for Mac.
+
+Alternatively, you can use uri connection by providing a single connection property
+[source,properties]
+----
+quarkus.infinispan-client.uri=hotrod://admin:password@localhost:11222 <1>
+quarkus.infinispan-client.client-intelligence=BASIC <2>
+----
+<1> Sets Infinispan URI connection. The following properties will be ignored: hosts, username and password.
+<2> Sets the client intelligence. Use BASIC as a workaround if using Docker for Mac
+
+[TIP]
+====
+Use Infinispan Dev Services to run a server and connect without configuration.
+====
+
+.Running Infinispan Server
+
+To use the Infinispan client extension, you need at least one running instance of Infinispan Server.
+
+Check out our 5-minute https://infinispan.org/get-started/[Getting stated with Infinispan] tutorial to run Infinispan Server locally.
+
+Infinispan Server also enables authentication and security authorization by default, so you need to create a user with permissions.
+
+* If you run the Infinispan Server image, pass the `USER="admin"` and `PASS="password"` parameters.
+* If you run the bare metal distribution, use the Command Line Interface (CLI) as follows:
++
+[source,bash]
+----
+$ ./bin/cli.sh user create admin -p password
+----
+
+=== Infinispan Health Check
+If you are using the quarkus-smallrye-health extension, the Infinispan client extensions will automatically add a readiness health check to validate the connection.
+
+When you access the `/q/health/ready` endpoint of your application you will have information about the server connection and available caches.
+
+This behavior can be disabled via the property `quarkus.infinispan-client.health.enabled`.
+
+=== Tracing with OpenTelemetry
+Infinispan supports instrumentation of the server via OpenTelemetry. Having the `quarkus-opentelemetry` extension will propagate
+the traces from the Infinispan Client to the Server.
+This behavior can be disabled via the property `quarkus.infinispan-client.tracing.propagation.enabled`
+
+=== Creating caches from the client
+
+When a cache is accessed from the client, if the cache does not exist in the Infinispan Server and you want
+to create it on first access, use one of the following properties:
+
+[source,properties]
+----
+quarkus.infinispan-client.cache.books.configuration-uri=cacheConfig.json <1>
+quarkus.infinispan-client.cache.magazine.configuration= <2>
+----
+<1> The file name located under the `resources` folder that contains the configuration of the 'books' cache
+<2> The configuration of the 'magazine' cache as a plain text property
+
+If both `configuration-uri` and `configuration` are configured for the same cache with the same Quarkus profile,
+`configuration-uri` gets preference over `configuration`.
+
+[TIP]
+====
+Cache configuration can be provided in XML, JSON or YAML. Use the Infinispan Console and the cache configuration Wizard
+to learn more about Infinispan Caches and create guided configurations.
+====
+
+If nothing is configured for a particular cache, it will be created with the following basic configuration:
+
+.XML
+[source,xml,options="nowrap",subs=attributes+,role="primary"]
+----
+
+
+
+----
+
+.JSON
+[source,json,options="nowrap",subs=attributes+,role="secondary"]
+----
+{
+ "distributed-cache": {
+ "encoding": {
+ "media-type": "application/x-protostream"
+ }
+ }
+}
+----
+
+.YAML
+[source,yaml,options="nowrap",subs=attributes+,role="secondary"]
+----
+distributedCache:
+ encoding:
+ mediaType: "application/x-protostream"
+----
+
+=== Authentication mechanisms
+
+You can use the following authentication mechanisms with the Infinispan client:
+
+* DIGEST-MD5
+* PLAIN (recommended only in combination with TLS encryption)
+* EXTERNAL
+
+Other authentication mechanisms, such as SCRAM and GSSAPI, are not yet verified with the Infinispan client.
+
+You can find more information on configuring authentication in https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#hotrod_endpoint_auth-hotrod-client-configuration[Hot Rod Endpoint Authentication Mechanisms].
+
+NOTE: You must configure authentication in the `hotrod-client.properties` file if you use Dependency Injection.
+
+== Serialization (Key Value types support)
+
+By default, the client will support keys and values of the following types: byte[],
+primitive wrappers (e.g. Integer, Long, Double), String, Date and Instant. User types require
+some additional steps that are detailed here. Let's say we have the following user classes:
+
+.Author.java
+[source,java]
+----
+public class Author {
+ private final String name;
+ private final String surname;
+
+ public Author(String name, String surname) {
+ this.name = Objects.requireNonNull(name);
+ this.surname = Objects.requireNonNull(surname);
+ }
+ // Getter/Setter/equals/hashCode/toString omitted
+}
+----
+
+.Book.java
+[source,java]
+----
+public class Book {
+ private final String title;
+ private final String description;
+ private final int publicationYear;
+ private final Set authors;
+ private final BigDecimal price;
+
+ public Book(String title, String description, int publicationYear, Set authors, BigDecimal price) {
+ this.title = Objects.requireNonNull(title);
+ this.description = Objects.requireNonNull(description);
+ this.publicationYear = publicationYear;
+ this.authors = Objects.requireNonNull(authors);
+ this.price = price;
+ }
+ // Getter/Setter/equals/hashCode/toString omitted
+}
+----
+
+Serialization of user types uses a library based on protobuf,
+called https://github.com/infinispan/protostream[Protostream].
+
+[TIP]
+====
+Infinispan caches can store keys and values in different encodings, but recommend using https://developers.google.com/protocol-buffers[Protocol Buffers (Protobuf)].
+
+For more information see our https://infinispan.org/docs/stable/titles/encoding/encoding.html[Cache Encoding and Marshalling] guide.
+====
+
+
+=== Annotation based Serialization
+
+This can be done automatically by adding protostream annotations to your user classes.
+In addition, a single Initializer annotated interface is required which controls how
+the supporting classes are generated.
+
+Here is an example of how the preceding classes should be changed:
+
+.Author.java
+[source,java]
+----
+ @ProtoFactory
+ public Author(String name, String surname) {
+ this.name = Objects.requireNonNull(name);
+ this.surname = Objects.requireNonNull(surname);
+ }
+
+ @ProtoField(number = 1)
+ public String getName() {
+ return name;
+ }
+
+ @ProtoField(number = 2)
+ public String getSurname() {
+ return surname;
+ }
+----
+
+.Book.java
+[source,java]
+----
+ @ProtoFactory
+ public Book(String title, String description, int publicationYear, Set authors) {
+ this.title = Objects.requireNonNull(title);
+ this.description = Objects.requireNonNull(description);
+ this.publicationYear = publicationYear;
+ this.authors = Objects.requireNonNull(authors);
+ }
+
+ @ProtoField(number = 1)
+ public String getTitle() {
+ return title;
+ }
+
+ @ProtoField(number = 2)
+ public String getDescription() {
+ return description;
+ }
+
+ @ProtoField(number = 3, defaultValue = "-1")
+ public int getPublicationYear() {
+ return publicationYear;
+ }
+
+ @ProtoField(number = 4)
+ public Set getAuthors() {
+ return authors;
+ }
+----
+
+If your classes have only mutable fields, then the `ProtoFactory` annotation
+is not required, assuming your class has a no arg constructor.
+
+Then all that is required is a very simple `GeneratedSchema` interface with an annotation
+on it to specify configuration settings
+
+.BooksSchema.java
+[source,java]
+----
+import org.infinispan.protostream.GeneratedSchema;
+import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
+import org.infinispan.protostream.types.java.math.BigDecimalAdapter;
+
+@AutoProtoSchemaBuilder(includeClasses = { Book.class, Author.class, BigDecimalAdapter.class }, schemaPackageName = "book_sample")
+interface BookStoreSchema extends GeneratedSchema {
+}
+----
+
+[TIP]
+====
+Protostream provides default Protobuf mappers for commonly used types as `BigDecimal`, included in the `org.infinispan.protostream.types` package.
+====
+
+So in this case we will automatically generate the marshaller and schemas for the included classes and
+place them in the schema package automatically. The package does not have to be provided, but if you use Infinispan search capabilities, you must know the generated package.
+
+NOTE: In Quarkus the `schemaFileName` and `schemaFilePath` attributes should NOT be set on the `AutoProtoSchemaBuilder` annotation. Setting either attributes causes native runtime errors.
+
+=== Custom serialization
+
+The previous method is suggested for any case when the user can annotate their classes.
+Unfortunately the user may not be able to annotate all classes they will put in the
+cache. In this case you must define your schema and create your own Marshaller(s)
+yourself.
+
+Protobuf schema:: You can supply a protobuf schema through either one of two ways.
+. Proto File
+ +
+You can put the `.proto` file in the `META-INF` directory of the project. These files will
+automatically be picked up at initialization time.
++
+.library.proto
+----
+package book_sample;
+
+message Book {
+ required string title = 1;
+ required string description = 2;
+ required int32 publicationYear = 3; // no native Date type available in Protobuf
+ repeated Author authors = 4;
+ requited double price = 5; // no native BigDecimal type available in Protobuf
+}
+
+message Author {
+ required string name = 1;
+ required string surname = 2;
+}
+----
+. In Code
+ +
+Or you can define the proto schema directly in user code by defining a produced bean of type
+`org.infinispan.protostream.FileDescriptorSource`.
++
+[source,java]
+----
+ @Produces
+ FileDescriptorSource bookProtoDefinition() {
+ return FileDescriptorSource.fromString("library.proto", "package book_sample;\n" +
+ "\n" +
+ "message Book {\n" +
+ " required string title = 1;\n" +
+ " required string description = 2;\n" +
+ " required int32 publicationYear = 3; // no native Date type available in Protobuf\n" +
+ "\n" +
+ " repeated Author authors = 4;\n" +
+ "\n" +
+ " required double price = 5; // no native BigDecimal type available in Protobuf\n" +
+ "}\n" +
+ "\n" +
+ "message Author {\n" +
+ " required string name = 1;\n" +
+ " required string surname = 2;\n" +
+ "}");
+ }
+----
+User Marshaller::
+The last thing to do is to provide a `org.infinispan.protostream.MessageMarshaller` implementation
+for each user class defined in the proto schema. This class is then provided via `@Produces` in a similar
+fashion to the code based proto schema definition above.
++
+Here is the Marshaller class for our Author & Book classes.
++
+NOTE: The type name must match the `.` exactly!
++
+.AuthorMarshaller.java
+[source,java]
+----
+public class AuthorMarshaller implements MessageMarshaller {
+
+ @Override
+ public String getTypeName() {
+ return "book_sample.Author";
+ }
+
+ @Override
+ public Class extends Author> getJavaClass() {
+ return Author.class;
+ }
+
+ @Override
+ public void writeTo(ProtoStreamWriter writer, Author author) throws IOException {
+ writer.writeString("name", author.getName());
+ writer.writeString("surname", author.getSurname());
+ }
+
+ @Override
+ public Author readFrom(ProtoStreamReader reader) throws IOException {
+ String name = reader.readString("name");
+ String surname = reader.readString("surname");
+ return new Author(name, surname);
+ }
+}
+----
++
+.BookMarshaller.java
+[source,java]
+----
+public class BookMarshaller implements MessageMarshaller {
+
+ @Override
+ public String getTypeName() {
+ return "book_sample.Book";
+ }
+
+ @Override
+ public Class extends Book> getJavaClass() {
+ return Book.class;
+ }
+
+ @Override
+ public void writeTo(ProtoStreamWriter writer, Book book) throws IOException {
+ writer.writeString("title", book.getTitle());
+ writer.writeString("description", book.getDescription());
+ writer.writeInt("publicationYear", book.getPublicationYear());
+ writer.writeCollection("authors", book.getAuthors(), Author.class);
+ writer.writeDouble("price", book.getPrice().doubleValue());
+ }
+
+ @Override
+ public Book readFrom(ProtoStreamReader reader) throws IOException {
+ String title = reader.readString("title");
+ String description = reader.readString("description");
+ int publicationYear = reader.readInt("publicationYear");
+ Set authors = reader.readCollection("authors", new HashSet<>(), Author.class);
+ BigDecimal price = BigDecimal.valueOf(reader.readDouble("price"));
+ return new Book(title, description, publicationYear, authors, price);
+ }
+}
+----
++
+And you pass the marshaller by defining the following:
++
+[source,java]
+----
+ @Produces
+ MessageMarshaller authorMarshaller() {
+ return new AuthorMarshaller();
+ }
+
+ @Produces
+ MessageMarshaller bookMarshaller() {
+ return new BookMarshaller();
+ }
+----
+NOTE: The above produced Marshaller method MUST return `MessageMarshaller` without types or else it will not be found.
+
+== Dependency Injection
+
+As you saw above we support the user injecting Marshaller configuration. You can do the inverse with
+the Infinispan client extension providing injection for `RemoteCacheManager` and `RemoteCache` objects.
+There is one global `RemoteCacheManager` that takes all the configuration
+parameters setup in the above sections.
+
+It is very simple to inject these components. All you need to do is to add the `@Inject` annotation to
+the field, constructor or method. In the below code we utilize field and constructor injection.
+
+.SomeClass.java
+[source,java]
+----
+ @Inject SomeClass(RemoteCacheManager remoteCacheManager) {
+ this.remoteCacheManager = remoteCacheManager;
+ }
+
+ @Inject
+ @Remote("myCache")
+ RemoteCache cache;
+
+ RemoteCacheManager remoteCacheManager;
+----
+
+If you notice the `RemoteCache` declaration has an additional optional annotation named `Remote`.
+This is a qualifier annotation allowing you to specify which named cache that will be injected. This
+annotation is not required and if it is not supplied, the default cache will be injected.
+
+NOTE: Other types may be supported for injection, please see other sections for more information
+
+=== Registering Protobuf Schemas with Infinispan Server
+You need to register the generated Protobuf schemas with Infinispan Server to perform queries or convert from
+`Protobuf` to other media types such as `JSON`.
+
+[TIP]
+====
+You can check the schemas that exist under the `Schemas` tab by logging into
+Infinispan Console at `http://SERVER_HOST:SERVER_PORT` (for example `http://localhost:11222`).
+
+Check the xref:infinispan-dev-services.adoc[Infinispan Dev Services Guide] to connect to the Infinispan
+Dev Services server.
+====
+
+By default, Protobuf schemas generated this way will be registered by this extension when the client first connects.
+However, it might be required to handle the registration manually as a schema may evolve over time when used in
+production, so you can disable this from occurring by configuring the
+`quarkus.infinispan-client.use-schema-registration` to `false`.
+
+To configure the schema manually
+please use https://infinispan.org/docs/infinispan-operator/main/operator.html[Infinispan Operator]
+for Kubernetes deployments, Infinispan Console,
+https://infinispan.org/docs/stable/titles/rest/rest.html#rest_v2_protobuf_schemas[REST API] or the
+https://infinispan.org/docs/stable/titles/encoding/encoding.html#registering-sci-remote-caches_marshalling[Hot Rod Java Client].
+
+[#infinispan-annotations-api]
+== Caching using annotations
+
+The Infinispan Client extension offers a set of annotations that can be used in a CDI managed bean to enable caching abilities with Infinispan.
+
+[WARNING]
+====
+Caching annotations are not allowed on private methods.
+They will work fine with any other access modifier including package-private (no explicit modifier).
+====
+
+=== @CacheResult
+
+Loads a method result from the cache without executing the method body whenever possible.
+
+When a method annotated with `@CacheResult` is invoked, Quarkus will use the method argument as the cache key and check in the cache whether the method has been already invoked.
+Methods with multiple parameters are not allowed. For composite keys, define a Protobuf schema that will hold multiple values.
+If a value is found in the cache, it is returned and the annotated method is never actually executed.
+If no value is found, the annotated method is invoked and the returned value is stored in the cache using the computed key.
+This annotation cannot be used on a method returning `void`.
+
+NOTE: Infinispan Client extension is not able yet to cache `null` values unlike the Quarkus-Cache extension.
+
+=== @CacheInvalidate
+
+Removes an entry from the cache.
+
+When a method annotated with `@CacheInvalidate` is invoked, Infinispan will use the method argument as a cache key to try to remove an existing entry from the cache.
+If the key does not identify any cache entry, nothing will happen.
+
+=== @CacheInvalidateAll
+
+When a method annotated with `@CacheInvalidateAll` is invoked, Infinispan will remove all entries from the cache.
+
+
+== Querying
+
+The Infinispan client supports both indexed and non-indexed search as long as the
+`ProtoStreamMarshaller` is configured above. This allows the user to query based on the
+properties of the proto schema. *Indexed queries are preferred for performance reasons*.
+
+.XML
+[source,xml,options="nowrap",subs=attributes+,role="primary"]
+----
+
+
+
+
+ book_sample.Book
+
+
+
+----
+
+.JSON
+[source,json,options="nowrap",subs=attributes+,role="secondary"]
+----
+{
+ "books": {
+ "distributed-cache": {
+ ...
+ "indexing": {
+ "enabled": true,
+ "storage": "filesystem",
+ "startupMode": "PURGE",
+ "indexed-entities": [
+ "book_sample.Book"
+ ]
+ }
+ }
+ }
+}
+----
+
+.YAML
+[source,yaml,options="nowrap",subs=attributes+,role="secondary"]
+----
+distributedCache:
+ # other configuration
+ indexing:
+ enabled: "true"
+ storage: "filesystem"
+ startupMode: "PURGE"
+ indexedEntities:
+ - "book_sample.Book"
+----
+
+Query builds upon the proto definitions you can configure when setting up the `ProtoStreamMarshaller`.
+Either method of Serialization above will automatically register the schema with the server at
+startup, meaning that you will automatically gain the ability to query objects stored in the
+remote Infinispan Server.
+
+.Book.java
+[source,java]
+----
+@Indexed <1>
+public class Book {
+
+ @ProtoFactory
+ public Book(String title, String description, int publicationYear, Set authors) {
+ ...
+ }
+
+ @ProtoField(number = 1)
+ @Text <2>
+ public String getTitle() {
+ return title;
+ }
+
+ @ProtoField(number = 2)
+ @Keyword(projectable = true, sortable = true, normalizer = "lowercase", indexNullAs = "unnamed", norms = false) <3>
+ public String getDescription() {
+ return description;
+ }
+ ...
+----
+<1> `@Indexed` annotation makes the POJO indexable
+<2> `@Basic` annotation is used for indexed fields without any special transformation
+<3> `@Keyword` annotation is used to apply a normalizer to a text field
+
+You can use either the Query DSL or the Ickle Query language with the Quarkus Infinispan client
+extension.
+
+NOTE: You can read more about https://infinispan.org/docs/stable/titles/query/query.html[querying] in the Infinispan documentation.
+
+
+== Counters
+
+Infinispan also has a notion of counters and the Quarkus Infinispan client supports them out of
+the box.
+
+The Quarkus Infinispan client extension allows for Dependency Injection
+of the `CounterManager` directly. All you need to do is annotate your field, constructor or method,
+and you get it with no fuss. You can then use counters as you would normally.
+
+[source,java]
+----
+@Inject
+CounterManager counterManager;
+----
+
+You can read more about https://infinispan.org/docs/stable/titles/developing/developing.html#clustered_counters[clustered counters] in the Infinispan documentation.
+
+== Near Caching
+
+Near caching is disabled by default, but you can enable it on a per cache basic by configuring the following properties:
+
+[source,properties]
+----
+quarkus.infinispan-client.cache.books.near-cache-mode=INVALIDATED <1>
+quarkus.infinispan-client.cache.books.near-cache-max-entries=200 <2>
+quarkus.infinispan-client.cache.books.near-cache-use-bloom-filter=true <3>
+----
+
+<1> Enables near caching for the 'books' cache by setting the mode to `INVALIDATED`
+<2> Sets the maximum number of entries that the near cache of the 'books' cache can hold before eviction occurs
+<3> Enables bloom filter for the 'books' cache
+
+=== Bounded near caching
+
+You should always use bounded near caches by specifying the maximum number of entries they can contain.
+
+=== Bloom filters
+
+If you need to optimize the performance for write operations by reducing the total number of invalidation messages,
+enable bloom filter. Bloom filters reside on Infinispan Server and keep track of the entries that the client has requested.
+They cannot be used with unbounded near cache: maximum number of entries must be defined when enabling bloom filters.
+
+== Encryption
+
+Encryption at this point requires additional steps to get working.
+
+The first step is to configure the `hotrod-client.properties` file to point to your truststore
+and/or keystore. This is further detailed https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#hotrod_encryption[here].
+
+The Infinispan Client extension enables SSL/TLS by default. You can read more about this
+at xref:native-and-ssl.adoc[Using SSL With Native Executables].
+
+== Additional Features
+
+The Infinispan Client has additional features that were not mentioned here. This means this
+feature was not tested in a Quarkus environment, and they may or may not work. Please let us
+know if you need these added!
+
+[[dev-services]]
+== Dev Services for Infinispan
+
+When you use the infinispan-client extension in dev mode or in test, Quarkus automatically starts an Infinispan server and configure your application.
+
+=== Enabling / Disabling Dev Services for Infinispan
+
+NOTE: Learn more in the xref:infinispan-dev-services.adoc[Infinispan Dev Services guide].
+
+== Shared server
+
+Quarkus will share the Infinispan broker if you have multiple applications running in dev mode.
+Dev Services for Infinispan implements a _service discovery_ mechanism for your multiple Quarkus applications running in _dev_ mode to share a single broker.
+
+NOTE: Dev Services for Infinispan starts the container with the `quarkus-dev-service-infinispan` label which is used to identify the container.
+
+If you need multiple (shared) Infinispan server, you can configure the `quarkus.infinispan-client.devservices.service-name` attribute and indicate the server name.
+It looks for a container with the same value, or starts a new one if none can be found.
+The default service name is `infinispan`.
+
+Sharing is enabled by default in dev mode, but disabled in test mode.
+You can disable the sharing with `quarkus.infinispan-client.devservices.shared=false`.
+
+== Setting the port
+
+By default, Dev Services for Infinispan picks a random port and configures the application.
+You can set the port by configuring the `quarkus.infinispan-client.devservices.port` property.
+
+== Testing helpers
+
+To start an Infinispan Server for your unit tests, Quarkus provides one `QuarkusTestResourceLifecycleManager` that relies on link:https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#junit-testing[Infinispan Server Test Container].
+
+- `io.quarkus.test.infinispan.client.InfinispanTestResource` will start a single instance on port 11222 with user 'admin' and password 'password'.
+
+To use them, you need to add the `io.quarkus:quarkus-test-infinispan-client` dependency to your pom.xml.
+
+For more information about the usage of a `QuarkusTestResourceLifecycleManager` please read xref:getting-started-testing.adoc#quarkus-test-resource[Quarkus test resource].
+
+== Configuration Reference
+
+include::{generated-dir}/config/quarkus-infinispan-client.adoc[opts=optional, leveloffset=+1]
diff --git a/docs/src/main/asciidoc/infinispan-client.adoc b/docs/src/main/asciidoc/infinispan-client.adoc
index 4e68b44e224fcf..160196ff297f06 100644
--- a/docs/src/main/asciidoc/infinispan-client.adoc
+++ b/docs/src/main/asciidoc/infinispan-client.adoc
@@ -3,33 +3,50 @@ This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
////
-= Infinispan Client
+= Using the Infinispan Client
include::_attributes.adoc[]
:categories: data
-:summary: Infinispan is an in memory distributed data store and cache server that offers flexible deployment options and robust capabilities for storing, managing, and processing data.
+:summary: This guide covers how to use Infinispan with Quarkus.
-Infinispan is a distributed, in-memory key/value store that provides Quarkus applications with a highly configurable
-and independently scalable data layer.
-This extension gives you client functionality that connects applications running on Quarkus with remote Infinispan clusters.
+This guide demonstrates how your Quarkus application can connect to an Infinispan server using the Infinispan Client extension.
-To find out more about Infinispan, visit the https://infinispan.org/documentation[Infinispan documentation].
+== Prerequisites
+
+include::{includes}/prerequisites.adoc[]
+* A working Docker environment
+
+== Architecture
+In this guide, we are going to expose a Greeting Rest API to create and display greeting messages by using
+the https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#remotecache_api[Infinispan RemoteCache API]
+and `getAsync` and `putAsync` operations.
+
+We'll be using the Quarkus Infinispan Client extension to connect to interact with Infinispan.
== Solution
+We recommend that you follow the instructions in the next sections and create the application step by step.
+However, you can go right to the completed example.
+
+Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive].
+
+The solution is located in the `infinispan-client-quickstart` {quickstarts-tree-url}/infinispan-client-quickstart[directory].
+
+== Creating the Maven Project
-We recommend that you complete each step in the following sections to create the application.
-However, you can proceed directly to the completed solution as follows:
+First, we need a new project. Create a new project with the following command:
-Clone the Git repository: `git clone {quickstarts-clone-url}` or download an {quickstarts-archive-url}[archive].
-Locate the solution in the `infinispan-client-quickstart` {quickstarts-tree-url}/infinispan-client-quickstart[directory].
+:create-app-artifact-id: infinispan-client-quickstart
+:create-app-extensions: infinispan-client,resteasy-reactive
+include::{includes}/devtools/create-app.adoc[]
-== Adding the Infinispan client extension
+This command generates a new project, importing the Infinispan Client extension.
-Run the following command in the base directory of your Quarkus project to add the `infinispan-client` extension:
+If you already have your Quarkus project configured, you can add the `infinispan-client` extension
+to your project by running the following command in your project base directory:
:add-extension-extensions: infinispan-client
include::{includes}/devtools/extension-add.adoc[]
-This command adds the following dependency to your build file:
+This will add the following to your build file:
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
.pom.xml
@@ -43,713 +60,294 @@ This command adds the following dependency to your build file:
[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
.build.gradle
----
-implementation 'io.quarkus:quarkus-infinispan-client'
-annotationProcessor 'org.infinispan.protostream:protostream-processor:4.5.1.Final' <1>
+implementation("io.quarkus:quarkus-infinispan-client")
+annotationProcessor 'org.infinispan.protostream:protostream-processor:4.6.1.Final' <1>
----
<1> Mandatory in the Gradle build to enable the generation of the files in the annotation based serialization
-== Configuring the Infinispan client
-
-Open the `application.properties` file in the `src/main/resources` directory with any text editor.
-
-Note that Infinispan documentation refers to a `hotrod-client.properties` file.
-You can configure the Infinispan client with either properties file but `application.properties` always takes
-priority over `hotrod-client.properties`.
-
-Additionally, you cannot update configuration properties at runtime.
-If you modify `application.properties` or `hotrod-client.properties`, you must rebuild the application before those changes take effect.
-
-== Connecting to Infinispan clusters
-
-If you are running an Infinispan Server add the following properties to connect:
+== Creating the Greeting POJO
+We are going to model our increments using the `Greeting` POJO.
+Create the `src/main/java/org/acme/infinispan/client/Greeting.java` file, with the following content:
-[source,properties]
+[source, java]
----
-quarkus.infinispan-client.hosts=localhost:11222 <1>
+package org.acme.infinispan.client;
-quarkus.infinispan-client.username=admin <2>
-quarkus.infinispan-client.password=password <3>
+import org.infinispan.protostream.annotations.ProtoFactory;
+import org.infinispan.protostream.annotations.ProtoField;
-quarkus.infinispan-client.client-intelligence=BASIC <4>
-----
-<1> Sets Infinispan Server address list, separated with commas
-<2> Sets the authentication username
-<3> Sets the authentication password
-<4> Sets the client intelligence. Use BASIC as a workaround if using Docker for Mac.
+public class Greeting { // <1>
+ @ProtoField(number = 1) // <2>
+ public String name;
-Alternatively, you can use uri connection by providing a single connection property
-[source,properties]
-----
-quarkus.infinispan-client.uri=hotrod://admin:password@localhost:11222 <1>
-quarkus.infinispan-client.client-intelligence=BASIC <2>
-----
-<1> Sets Infinispan URI connection. The following properties will be ignored: hosts, username and password.
-<2> Sets the client intelligence. Use BASIC as a workaround if using Docker for Mac
-
-[TIP]
-====
-Use Infinispan Dev Services to run a server and connect without configuration.
-====
-
-.Running Infinispan Server
-
-To use the Infinispan client extension, you need at least one running instance of Infinispan Server.
-
-Check out our 5-minute https://infinispan.org/get-started/[Getting stated with Infinispan] tutorial to run Infinispan Server locally.
-
-Infinispan Server also enables authentication and security authorization by default, so you need to create a user with permissions.
-
-* If you run the Infinispan Server image, pass the `USER="admin"` and `PASS="password"` parameters.
-* If you run the bare metal distribution, use the Command Line Interface (CLI) as follows:
-+
-[source,bash]
-----
-$ ./bin/cli.sh user create admin -p password
+ @ProtoField(number = 2) // <3>
+ public String message;
+}
----
+<1> If your classes have only mutable fields, then the `ProtoFactory` annotation is not required
+is not required, assuming your class has a no arg constructor
+<2> `@ProtoField` annotation to add the name fieldto as string in the generated Protobuf schema
+<3> `@ProtoField` annotation to add the message field to as string in the generated Protobuf schema
-=== Infinispan Health Check
-If you are using the quarkus-smallrye-health extension, the Infinispan client extensions will automatically add a readiness health check to validate the connection.
-
-When you access the `/q/health/ready` endpoint of your application you will have information about the server connection and available caches.
-
-This behavior can be disabled via the property `quarkus.infinispan-client.health.enabled`.
-
-=== Tracing with OpenTelemetry
-Infinispan supports instrumentation of the server via OpenTelemetry. Having the `quarkus-opentelemetry` extension will propagate
-the traces from the Infinispan Client to the Server.
-This behavior can be disabled via the property `quarkus.infinispan-client.tracing.propagation.enabled`
+Note that we are not going to use Java serialization. https://github.com/infinispan/protostream[Protostream] is
+a serialization library based on Protobuf data format part of Infinispan. Using an annotation based API, we
+will store our data in Protobuf format.
-=== Creating caches from the client
+== Creating the Greeting Schema
+We are going to create our serialization schema using the `GreetingSchema` interface.
+Create the `src/main/java/org/acme/infinispan/client/GreetingSchema.java` file, with the following content:
-When a cache is accessed from the client, if the cache does not exist in the Infinispan Server and you want
-to create it on first access, use one of the following properties:
-
-[source,properties]
-----
-quarkus.infinispan-client.cache.books.configuration-uri=cacheConfig.json <1>
-quarkus.infinispan-client.cache.magazine.configuration= <2>
+[source, java]
----
-<1> The file name located under the `resources` folder that contains the configuration of the 'books' cache
-<2> The configuration of the 'magazine' cache as a plain text property
-
-If both `configuration-uri` and `configuration` are configured for the same cache with the same Quarkus profile,
-`configuration-uri` gets preference over `configuration`.
-
-[TIP]
-====
-Cache configuration can be provided in XML, JSON or YAML. Use the Infinispan Console and the cache configuration Wizard
-to learn more about Infinispan Caches and create guided configurations.
-====
-
-If nothing is configured for a particular cache, it will be created with the following basic configuration:
+package org.acme.infinispan.client;
-.XML
-[source,xml,options="nowrap",subs=attributes+,role="primary"]
-----
-
-
-
-----
+import org.infinispan.protostream.GeneratedSchema;
+import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
-.JSON
-[source,json,options="nowrap",subs=attributes+,role="secondary"]
-----
-{
- "distributed-cache": {
- "encoding": {
- "media-type": "application/x-protostream"
- }
- }
+@AutoProtoSchemaBuilder(includeClasses = Greeting.class) // <1>
+public interface GreetingSchema extends GeneratedSchema { // <2>
}
----
+<1> Includes the `Greeting` pojo with the `@AutoProtoSchemaBuilder` annotation
+<2> Extends `GeneratedSchema` Protostream API interface
-.YAML
-[source,yaml,options="nowrap",subs=attributes+,role="secondary"]
-----
-distributedCache:
- encoding:
- mediaType: "application/x-protostream"
-----
-
-=== Authentication mechanisms
-
-You can use the following authentication mechanisms with the Infinispan client:
-
-* DIGEST-MD5
-* PLAIN (recommended only in combination with TLS encryption)
-* EXTERNAL
-
-Other authentication mechanisms, such as SCRAM and GSSAPI, are not yet verified with the Infinispan client.
+The Protobuf Schema that will be generated and used both on client and Infinispan Server side, will have
+the following content:
-You can find more information on configuring authentication in https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#hotrod_endpoint_auth-hotrod-client-configuration[Hot Rod Endpoint Authentication Mechanisms].
-
-NOTE: You must configure authentication in the `hotrod-client.properties` file if you use Dependency Injection.
-
-== Serialization (Key Value types support)
-
-By default, the client will support keys and values of the following types: byte[],
-primitive wrappers (e.g. Integer, Long, Double), String, Date and Instant. User types require
-some additional steps that are detailed here. Let's say we have the following user classes:
-
-.Author.java
-[source,java]
-----
-public class Author {
- private final String name;
- private final String surname;
-
- public Author(String name, String surname) {
- this.name = Objects.requireNonNull(name);
- this.surname = Objects.requireNonNull(surname);
- }
- // Getter/Setter/equals/hashCode/toString omitted
-}
+[source, protobuf]
----
+// File name: GreetingSchema.proto
+// Generated from : org.acme.infinispan.client.GreetingSchema
-.Book.java
-[source,java]
-----
-public class Book {
- private final String title;
- private final String description;
- private final int publicationYear;
- private final Set authors;
- private final BigDecimal price;
-
- public Book(String title, String description, int publicationYear, Set authors, BigDecimal price) {
- this.title = Objects.requireNonNull(title);
- this.description = Objects.requireNonNull(description);
- this.publicationYear = publicationYear;
- this.authors = Objects.requireNonNull(authors);
- this.price = price;
- }
- // Getter/Setter/equals/hashCode/toString omitted
-}
-----
+syntax = "proto2";
-Serialization of user types uses a library based on protobuf,
-called https://github.com/infinispan/protostream[Protostream].
+message Greeting {
-[TIP]
-====
-Infinispan caches can store keys and values in different encodings, but recommend using https://developers.google.com/protocol-buffers[Protocol Buffers (Protobuf)].
+ optional string name = 1;
-For more information see our https://infinispan.org/docs/stable/titles/encoding/encoding.html[Cache Encoding and Marshalling] guide.
-====
-
-
-=== Annotation based Serialization
-
-This can be done automatically by adding protostream annotations to your user classes.
-In addition, a single Initializer annotated interface is required which controls how
-the supporting classes are generated.
-
-Here is an example of how the preceding classes should be changed:
-
-.Author.java
-[source,java]
+ optional string message = 2;
+}
----
- @ProtoFactory
- public Author(String name, String surname) {
- this.name = Objects.requireNonNull(name);
- this.surname = Objects.requireNonNull(surname);
- }
- @ProtoField(number = 1)
- public String getName() {
- return name;
- }
+== Creating the Infinispan Greeting Resource
+Create the `src/main/java/org/acme/infinispan/client/InfinispanGreetingResource.java` file, with the following content:
- @ProtoField(number = 2)
- public String getSurname() {
- return surname;
- }
+[source, java]
----
+package org.acme.infinispan.client;
-.Book.java
-[source,java]
-----
- @ProtoFactory
- public Book(String title, String description, int publicationYear, Set authors) {
- this.title = Objects.requireNonNull(title);
- this.description = Objects.requireNonNull(description);
- this.publicationYear = publicationYear;
- this.authors = Objects.requireNonNull(authors);
- }
+import io.quarkus.infinispan.client.Remote;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import org.infinispan.client.hotrod.RemoteCache;
- @ProtoField(number = 1)
- public String getTitle() {
- return title;
- }
+import java.util.concurrent.CompletionStage;
- @ProtoField(number = 2)
- public String getDescription() {
- return description;
- }
+@Path("/greeting")
+public class InfinispanGreetingResource {
- @ProtoField(number = 3, defaultValue = "-1")
- public int getPublicationYear() {
- return publicationYear;
+ @Inject
+ @Remote("mycache") // <1>
+ RemoteCache cache; //<2>
+
+ @POST
+ @Path("/{id}")
+ public CompletionStage postGreeting(String id, Greeting greeting) {
+ return cache.putAsync(id, greeting) // <3>
+ .thenApply(g -> "Greeting done!")
+ .exceptionally(ex -> ex.getMessage());
}
- @ProtoField(number = 4)
- public Set getAuthors() {
- return authors;
+ @GET
+ @Path("/{id}")
+ public CompletionStage getGreeting(String id) {
+ return cache.getAsync(id); // <4>
}
+}
----
+<1> Use the `@Remote` annotation to use a cache. If the cache does not exist, will be created with a
+default configuration *on first access*.
+<2> Inject the `RemoteCache`
+<3> Put the greeting id as a key and the Greeting pojo as a value
+<4> Get the greeting by id as the key
-If your classes have only mutable fields, then the `ProtoFactory` annotation
-is not required, assuming your class has a no arg constructor.
+== Creating the test class
-Then all that is required is a very simple `GeneratedSchema` interface with an annotation
-on it to specify configuration settings
+Edit the `pom.xml` file to add the following dependency:
-.BooksSchema.java
-[source,java]
+[source, xml]
----
-import org.infinispan.protostream.GeneratedSchema;
-import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
-import org.infinispan.protostream.types.java.math.BigDecimalAdapter;
-
-@AutoProtoSchemaBuilder(includeClasses = { Book.class, Author.class, BigDecimalAdapter.class }, schemaPackageName = "book_sample")
-interface BookStoreSchema extends GeneratedSchema {
-}
+
+ io.rest-assured
+ rest-assured
+ test
+
----
-[TIP]
-====
-Protostream provides default Protobuf mappers for commonly used types as `BigDecimal`, included in the `org.infinispan.protostream.types` package.
-====
-
-So in this case we will automatically generate the marshaller and schemas for the included classes and
-place them in the schema package automatically. The package does not have to be provided, but if you use Infinispan search capabilities, you must know the generated package.
-
-NOTE: In Quarkus the `schemaFileName` and `schemaFilePath` attributes should NOT be set on the `AutoProtoSchemaBuilder` annotation. Setting either attributes causes native runtime errors.
+Create the `src/test/java/org/acme/infinispan/client/InfinispanGreetingResourceTest.java` file with the following content:
-=== Custom serialization
-The previous method is suggested for any case when the user can annotate their classes.
-Unfortunately the user may not be able to annotate all classes they will put in the
-cache. In this case you must define your schema and create your own Marshaller(s)
-yourself.
-
-Protobuf schema:: You can supply a protobuf schema through either one of two ways.
-. Proto File
- +
-You can put the `.proto` file in the `META-INF` directory of the project. These files will
-automatically be picked up at initialization time.
-+
-.library.proto
+[source, java]
----
-package book_sample;
-
-message Book {
- required string title = 1;
- required string description = 2;
- required int32 publicationYear = 3; // no native Date type available in Protobuf
- repeated Author authors = 4;
- requited double price = 5; // no native BigDecimal type available in Protobuf
-}
+package org.acme.infinispan.client;
-message Author {
- required string name = 1;
- required string surname = 2;
-}
-----
-. In Code
- +
-Or you can define the proto schema directly in user code by defining a produced bean of type
-`org.infinispan.protostream.FileDescriptorSource`.
-+
-[source,java]
-----
- @Produces
- FileDescriptorSource bookProtoDefinition() {
- return FileDescriptorSource.fromString("library.proto", "package book_sample;\n" +
- "\n" +
- "message Book {\n" +
- " required string title = 1;\n" +
- " required string description = 2;\n" +
- " required int32 publicationYear = 3; // no native Date type available in Protobuf\n" +
- "\n" +
- " repeated Author authors = 4;\n" +
- "\n" +
- " required double price = 5; // no native BigDecimal type available in Protobuf\n" +
- "}\n" +
- "\n" +
- "message Author {\n" +
- " required string name = 1;\n" +
- " required string surname = 2;\n" +
- "}");
- }
-----
-User Marshaller::
-The last thing to do is to provide a `org.infinispan.protostream.MessageMarshaller` implementation
-for each user class defined in the proto schema. This class is then provided via `@Produces` in a similar
-fashion to the code based proto schema definition above.
-+
-Here is the Marshaller class for our Author & Book classes.
-+
-NOTE: The type name must match the `.` exactly!
-+
-.AuthorMarshaller.java
-[source,java]
-----
-public class AuthorMarshaller implements MessageMarshaller {
-
- @Override
- public String getTypeName() {
- return "book_sample.Author";
- }
-
- @Override
- public Class extends Author> getJavaClass() {
- return Author.class;
- }
-
- @Override
- public void writeTo(ProtoStreamWriter writer, Author author) throws IOException {
- writer.writeString("name", author.getName());
- writer.writeString("surname", author.getSurname());
- }
-
- @Override
- public Author readFrom(ProtoStreamReader reader) throws IOException {
- String name = reader.readString("name");
- String surname = reader.readString("surname");
- return new Author(name, surname);
- }
-}
-----
-+
-.BookMarshaller.java
-[source,java]
-----
-public class BookMarshaller implements MessageMarshaller {
-
- @Override
- public String getTypeName() {
- return "book_sample.Book";
- }
-
- @Override
- public Class extends Book> getJavaClass() {
- return Book.class;
- }
-
- @Override
- public void writeTo(ProtoStreamWriter writer, Book book) throws IOException {
- writer.writeString("title", book.getTitle());
- writer.writeString("description", book.getDescription());
- writer.writeInt("publicationYear", book.getPublicationYear());
- writer.writeCollection("authors", book.getAuthors(), Author.class);
- writer.writeDouble("price", book.getPrice().doubleValue());
- }
-
- @Override
- public Book readFrom(ProtoStreamReader reader) throws IOException {
- String title = reader.readString("title");
- String description = reader.readString("description");
- int publicationYear = reader.readInt("publicationYear");
- Set authors = reader.readCollection("authors", new HashSet<>(), Author.class);
- BigDecimal price = BigDecimal.valueOf(reader.readDouble("price"));
- return new Book(title, description, publicationYear, authors, price);
- }
-}
-----
-+
-And you pass the marshaller by defining the following:
-+
-[source,java]
-----
- @Produces
- MessageMarshaller authorMarshaller() {
- return new AuthorMarshaller();
- }
-
- @Produces
- MessageMarshaller bookMarshaller() {
- return new BookMarshaller();
- }
-----
-NOTE: The above produced Marshaller method MUST return `MessageMarshaller` without types or else it will not be found.
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.Test;
-== Dependency Injection
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.is;
-As you saw above we support the user injecting Marshaller configuration. You can do the inverse with
-the Infinispan client extension providing injection for `RemoteCacheManager` and `RemoteCache` objects.
-There is one global `RemoteCacheManager` that takes all the configuration
-parameters setup in the above sections.
+@QuarkusTest
+class InfinispanGreetingResourceTest {
-It is very simple to inject these components. All you need to do is to add the `@Inject` annotation to
-the field, constructor or method. In the below code we utilize field and constructor injection.
+ @Test
+ public void testHelloEndpoint() {
+ given()
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"Infinispan Client\",\"message\":\"Hello World, Infinispan is up!\"}")
+ .when()
+ .post("/greeting/quarkus")
+ .then()
+ .statusCode(200);
-.SomeClass.java
-[source,java]
-----
- @Inject SomeClass(RemoteCacheManager remoteCacheManager) {
- this.remoteCacheManager = remoteCacheManager;
+ given()
+ .when().get("/greeting/quarkus")
+ .then()
+ .statusCode(200)
+ .body(is("{\"name\":\"Infinispan Client\",\"message\":\"Hello World, Infinispan is up!\"}"));
}
-
- @Inject
- @Remote("myCache")
- RemoteCache cache;
-
- RemoteCacheManager remoteCacheManager;
+}
----
-If you notice the `RemoteCache` declaration has an additional optional annotation named `Remote`.
-This is a qualifier annotation allowing you to specify which named cache that will be injected. This
-annotation is not required and if it is not supplied, the default cache will be injected.
+== Get it running
-NOTE: Other types may be supported for injection, please see other sections for more information
+We just need to run the application using:
-=== Registering Protobuf Schemas with Infinispan Server
-You need to register the generated Protobuf schemas with Infinispan Server to perform queries or convert from
-`Protobuf` to other media types such as `JSON`.
+include::{includes}/devtools/dev.adoc[]
-[TIP]
-====
-You can check the schemas that exist under the `Schemas` tab by logging into
-Infinispan Console at `http://SERVER_HOST:SERVER_PORT` (for example `http://localhost:11222`).
+We should have the Infinispan server running thanks to the Dev Services.
+We can access the Dev Services UI through `http://localhost:8080/q/dev/`.
+The Dev UI should display the Infinispan UI Panel.
-Check the xref:infinispan-dev-services.adoc[Infinispan Dev Services Guide] to connect to the Infinispan
-Dev Services server.
-====
+image::dev-ui-infinispan.png[alt=Dev UI Infinispan,align=center,width=40%]
-By default, Protobuf schemas generated this way will be registered by this extension when the client first connects.
-However, it might be required to handle the registration manually as a schema may evolve over time when used in
-production, so you can disable this from occurring by configuring the
-`quarkus.infinispan-client.use-schema-registration` to `false`.
-
-To configure the schema manually
-please use https://infinispan.org/docs/infinispan-operator/main/operator.html[Infinispan Operator]
-for Kubernetes deployments, Infinispan Console,
-https://infinispan.org/docs/stable/titles/rest/rest.html#rest_v2_protobuf_schemas[REST API] or the
-https://infinispan.org/docs/stable/titles/encoding/encoding.html#registering-sci-remote-caches_marshalling[Hot Rod Java Client].
-
-[#infinispan-annotations-api]
-== Caching using annotations
-
-The Infinispan Client extension offers a set of annotations that can be used in a CDI managed bean to enable caching abilities with Infinispan.
-
-[WARNING]
+[TIP]
====
-Caching annotations are not allowed on private methods.
-They will work fine with any other access modifier including package-private (no explicit modifier).
+Click on the Web Console link and log using `admin` and `password` default credentials.
+Quarkus has uploaded into the Schemas Tab the Protobuf Schema that is needed to marshall on the server the
+Greeting POJO with Protobuf.
+Check the xref:infinispan-dev-services.adoc[Infinispan Dev Services Guide] to learn more.
====
-=== @CacheResult
-
-Loads a method result from the cache without executing the method body whenever possible.
-
-When a method annotated with `@CacheResult` is invoked, Quarkus will use the method argument as the cache key and check in the cache whether the method has been already invoked.
-Methods with multiple parameters are not allowed. For composite keys, define a Protobuf schema that will hold multiple values.
-If a value is found in the cache, it is returned and the annotated method is never actually executed.
-If no value is found, the annotated method is invoked and the returned value is stored in the cache using the computed key.
-This annotation cannot be used on a method returning `void`.
-
-NOTE: Infinispan Client extension is not able yet to cache `null` values unlike the Quarkus-Cache extension.
-
-=== @CacheInvalidate
-
-Removes an entry from the cache.
-
-When a method annotated with `@CacheInvalidate` is invoked, Infinispan will use the method argument as a cache key to try to remove an existing entry from the cache.
-If the key does not identify any cache entry, nothing will happen.
-
-=== @CacheInvalidateAll
-
-When a method annotated with `@CacheInvalidateAll` is invoked, Infinispan will remove all entries from the cache.
-
-
-== Querying
+== Interacting with the Greeting Service
+As we have seen above, the Greeting API exposes two Rest endpoints.
+In this section we are going to see how to create and display a greeting message.
-The Infinispan client supports both indexed and non-indexed search as long as the
-`ProtoStreamMarshaller` is configured above. This allows the user to query based on the
-properties of the proto schema. *Indexed queries are preferred for performance reasons*.
+=== Creating a Greeting Message
+With the following command, we will create a greeting message with the id `quarkus`.
-.XML
-[source,xml,options="nowrap",subs=attributes+,role="primary"]
+[source,bash]
----
-
-
-
-
- book_sample.Book
-
-
-
+curl -X POST http://localhost:8080/greeting/quarkus -H "Content-Type: application/json" -d '{"name" : "Infinispan Client", "message":"Hello World, Infinispan is up!"}'
----
-.JSON
-[source,json,options="nowrap",subs=attributes+,role="secondary"]
-----
-{
- "books": {
- "distributed-cache": {
- ...
- "indexing": {
- "enabled": true,
- "storage": "filesystem",
- "startupMode": "PURGE",
- "indexed-entities": [
- "book_sample.Book"
- ]
- }
- }
- }
-}
-----
+The service should respond with a `Greeting added!` message.
-.YAML
-[source,yaml,options="nowrap",subs=attributes+,role="secondary"]
+=== Displaying a Greeting Message
+With the following command, we will display the greeting message with the id `quarkus`.
+[source,bash]
----
-distributedCache:
- # other configuration
- indexing:
- enabled: "true"
- storage: "filesystem"
- startupMode: "PURGE"
- indexedEntities:
- - "book_sample.Book"
+curl http://localhost:8080/greeting/quarkus
----
-Query builds upon the proto definitions you can configure when setting up the `ProtoStreamMarshaller`.
-Either method of Serialization above will automatically register the schema with the server at
-startup, meaning that you will automatically gain the ability to query objects stored in the
-remote Infinispan Server.
+The service should respond with the following json content.
-.Book.java
-[source,java]
+[source, json]
----
-@Indexed <1>
-public class Book {
-
- @ProtoFactory
- public Book(String title, String description, int publicationYear, Set authors) {
- ...
- }
-
- @ProtoField(number = 1)
- @Text <2>
- public String getTitle() {
- return title;
- }
-
- @ProtoField(number = 2)
- @Keyword(projectable = true, sortable = true, normalizer = "lowercase", indexNullAs = "unnamed", norms = false) <3>
- public String getDescription() {
- return description;
- }
- ...
+{
+ "name" : "Infinispan Client",
+ "message" : "Hello World, Infinispan is up!"
+}
----
-<1> `@Indexed` annotation makes the POJO indexable
-<2> `@Basic` annotation is used for indexed fields without any special transformation
-<3> `@Keyword` annotation is used to apply a normalizer to a text field
-You can use either the Query DSL or the Ickle Query language with the Quarkus Infinispan client
-extension.
+=== Display the cache and content with the Infinispan Server Console
-NOTE: You can read more about https://infinispan.org/docs/stable/titles/query/query.html[querying] in the Infinispan documentation.
+If a requested cache does not exist, Quarkus creates a cache with a Default configuration on first access.
+We should be able to reaload the Infinispan Server Console and display the content of the Cache.
+The Infinispan Server Console uses the https://infinispan.org/docs/stable/titles/rest/rest.html[Infinispan Server REST API].
+The content can be displayed in JSON thanks to the Protobuf Encoding that converts to JSON format.
+image::infinispan-console-client-guide.png[alt=Infinispan Console,align=center,width=90%]
-== Counters
-Infinispan also has a notion of counters and the Quarkus Infinispan client supports them out of
-the box.
+== Configuring for production
-The Quarkus Infinispan client extension allows for Dependency Injection
-of the `CounterManager` directly. All you need to do is annotate your field, constructor or method,
-and you get it with no fuss. You can then use counters as you would normally.
+At this point, Quarkus uses the Infinispan Dev Service to run an Infinispan server and configure the application.
+However, in production, you will run your own Infinispan (or Red Hat Data Grid).
-[source,java]
-----
-@Inject
-CounterManager counterManager;
-----
+Let's start an Infinispan server on the port 11222 using:
-You can read more about https://infinispan.org/docs/stable/titles/developing/developing.html#clustered_counters[clustered counters] in the Infinispan documentation.
-
-== Near Caching
-
-Near caching is disabled by default, but you can enable it on a per cache basic by configuring the following properties:
-
-[source,properties]
+[source, shell]
----
-quarkus.infinispan-client.cache.books.near-cache-mode=INVALIDATED <1>
-quarkus.infinispan-client.cache.books.near-cache-max-entries=200 <2>
-quarkus.infinispan-client.cache.books.near-cache-use-bloom-filter=true <3>
+docker run -it -p 11222:11222 -e USER="admin" -e PASS="password" quay.io/infinispan/server:latest
----
-<1> Enables near caching for the 'books' cache by setting the mode to `INVALIDATED`
-<2> Sets the maximum number of entries that the near cache of the 'books' cache can hold before eviction occurs
-<3> Enables bloom filter for the 'books' cache
-
-=== Bounded near caching
-
-You should always use bounded near caches by specifying the maximum number of entries they can contain.
+Then, open the `src/main/resources/application.properties` file and add:
-=== Bloom filters
-
-If you need to optimize the performance for write operations by reducing the total number of invalidation messages,
-enable bloom filter. Bloom filters reside on Infinispan Server and keep track of the entries that the client has requested.
-They cannot be used with unbounded near cache: maximum number of entries must be defined when enabling bloom filters.
-
-== Encryption
-
-Encryption at this point requires additional steps to get working.
-
-The first step is to configure the `hotrod-client.properties` file to point to your truststore
-and/or keystore. This is further detailed https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#hotrod_encryption[here].
-
-The Infinispan Client extension enables SSL/TLS by default. You can read more about this
-at xref:native-and-ssl.adoc[Using SSL With Native Executables].
-
-== Additional Features
-
-The Infinispan Client has additional features that were not mentioned here. This means this
-feature was not tested in a Quarkus environment, and they may or may not work. Please let us
-know if you need these added!
-
-[[dev-services]]
-== Dev Services for Infinispan
-
-When you use the infinispan-client extension in dev mode or in test, Quarkus automatically starts an Infinispan server and configure your application.
+[source, properties]
+----
+%prod.quarkus.infinispan-client.hosts=localhost:11222 # <1>
+%prod.quarkus.infinispan-client.username=admin <2>
+%prod.quarkus.infinispan-client.password=password <3>
-=== Enabling / Disabling Dev Services for Infinispan
+## Docker 4 Mac workaround
+%prod.quarkus.infinispan-client.client-intelligence=BASIC <4>
+----
+<1> Sets Infinispan Server address list, separated with commas
+<2> Sets the authentication username
+<3> Sets the authentication password
+<4> Sets the client intelligence. Use BASIC as a workaround if using Docker for Mac.
-NOTE: Learn more in the xref:infinispan-dev-services.adoc[Infinispan Dev Services guide].
+== Packaging and running in JVM mode
-== Shared server
+You can run the application as a conventional jar file.
-Quarkus will share the Infinispan broker if you have multiple applications running in dev mode.
-Dev Services for Infinispan implements a _service discovery_ mechanism for your multiple Quarkus applications running in _dev_ mode to share a single broker.
+First, we will need to package it:
-NOTE: Dev Services for Infinispan starts the container with the `quarkus-dev-service-infinispan` label which is used to identify the container.
+include::{includes}/devtools/build.adoc[]
-If you need multiple (shared) Infinispan server, you can configure the `quarkus.infinispan-client.devservices.service-name` attribute and indicate the server name.
-It looks for a container with the same value, or starts a new one if none can be found.
-The default service name is `infinispan`.
+NOTE: This command will start an Infinispan instance to execute the tests.
-Sharing is enabled by default in dev mode, but disabled in test mode.
-You can disable the sharing with `quarkus.infinispan-client.devservices.shared=false`.
+Then run it:
-== Setting the port
+[source,bash]
+----
+java -jar target/quarkus-app/quarkus-run.jar
+----
-By default, Dev Services for Infinispan picks a random port and configures the application.
-You can set the port by configuring the `quarkus.infinispan-client.devservices.port` property.
+== Running Native
-== Testing helpers
+You can also create a native executable from this application without making any
+source code changes. A native executable removes the dependency on the JVM:
+everything needed to run the application on the target platform is included in
+the executable, allowing the application to run with minimal resource overhead.
-To start an Infinispan Server for your unit tests, Quarkus provides one `QuarkusTestResourceLifecycleManager` that relies on link:https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#junit-testing[Infinispan Server Test Container].
+Compiling a native executable takes a bit longer, as GraalVM performs additional
+steps to remove unnecessary codepaths. Use the `native` profile to compile a
+native executable:
-- `io.quarkus.test.infinispan.client.InfinispanTestResource` will start a single instance on port 11222 with user 'admin' and password 'password'.
+include::{includes}/devtools/build-native.adoc[]
-To use them, you need to add the `io.quarkus:quarkus-test-infinispan-client` dependency to your pom.xml.
+Once the build is finished, you can run the executable with:
-For more information about the usage of a `QuarkusTestResourceLifecycleManager` please read xref:getting-started-testing.adoc#quarkus-test-resource[Quarkus test resource].
+[source,bash]
+----
+./target/infinispan-client-quickstart-1.0.0-SNAPSHOT-runner
+----
-== Configuration Reference
+== Going further
-include::{generated-dir}/config/quarkus-infinispan-client.adoc[opts=optional, leveloffset=+1]
+To learn more about the Quarkus Infinispan extension, check xref:infinispan-client-reference.adoc[the Infinispan Client extension reference guide].