{"id":28385408,"url":"https://github.com/infinispan/infinispan-server-tutorial","last_synced_at":"2025-06-26T06:31:39.590Z","repository":{"id":39284240,"uuid":"248842639","full_name":"infinispan/infinispan-server-tutorial","owner":"infinispan","description":"Infinispan Server Tutorial Guide","archived":false,"fork":false,"pushed_at":"2025-02-03T10:55:30.000Z","size":2523,"stargazers_count":6,"open_issues_count":2,"forks_count":8,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-05-30T12:18:21.049Z","etag":null,"topics":["infinispan","infinispan-server","tutorial"],"latest_commit_sha":null,"homepage":"https://infinispan.org/infinispan-server-tutorial","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/infinispan.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-20T20:08:03.000Z","updated_at":"2025-04-24T16:02:28.000Z","dependencies_parsed_at":"2024-05-17T15:27:11.995Z","dependency_job_id":"434b2495-15cf-446b-9931-ba414035bf0f","html_url":"https://github.com/infinispan/infinispan-server-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/infinispan/infinispan-server-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinispan%2Finfinispan-server-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinispan%2Finfinispan-server-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinispan%2Finfinispan-server-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinispan%2Finfinispan-server-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infinispan","download_url":"https://codeload.github.com/infinispan/infinispan-server-tutorial/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinispan%2Finfinispan-server-tutorial/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262014573,"owners_count":23245157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["infinispan","infinispan-server","tutorial"],"created_at":"2025-05-30T10:39:39.766Z","updated_at":"2025-06-26T06:31:39.569Z","avatar_url":"https://github.com/infinispan.png","language":"Java","readme":":toc: left\n:toclevels: 4\n:source-highlighter: highlightjs\n:icons: font\n:imagesdir: ./images\n\nimage::infinispan_logo.svg[Infinispan Logo]\n\n== Infinispan Remote Weather App Tutorial\n\nLearn how to use Infinispan from the Console and remote Hot Rod clients. This\ntutorial includes Java applications that use Infinispan capabilities to provide\nservices for a searchable weather monitoring system.\n\n=== Objectives\n\nBy completing this tutorial, you will learn how to:\n\n. Run Infinispan Server.\n. Access and use the Infinispan Console.\n. Create Infinispan caches.\n. Read and write data as primitive types and Java objects.\n. Add lifespans to entries so data expires.\n. Deploy client listeners to get event notifications.\n. Search the data store for specific values.\n. Use out-of-the-box testing with Junit 5 for verification.\n\n=== Prerequisites\n\nTo complete this tutorial, you need:\n\n- Approximately 25 to 30 minutes\n- IDE such as Eclipse or Intellij\n- JDK 17 or later\n- https://www.docker.com/[Docker] or https://podman.io/[Podman]\n\n[TIP]\n====\nRun `mvn --version` to verify that Maven uses the correct JDK if you have\nmultiple Java versions installed.\n====\n\n=== Weather System Architecture\n\nThis tutorial builds a Weather System with the following Java applications:\n\n. `TemperatureLoaderApp`\n. `TemperatureMonitorApp`\n. `WeatherLoaderApp`\n. `WeatherFinderApp`\n\n==== Temperature Subsystem\n\nThe Temperature Loader and Temperature Monitor applications comprise the temperature subsystem, as shown below:\n\nimage::Temperature.png[Temperature.png]\n\n===== Temperature Loader\n\nThis application loads temperatures for geographic locations and runs every five seconds. Infinispan stores that data in the `temperature` cache as follows:\n\n- Location: Key `String`\n- Temperature: Value `Float`\n\n===== Temperature Monitor\n\nThis application monitors the temperature of each location. Infinispan sends notifications when temperatures change and the application displays each new temperature.\n\n==== Weather Subsystem\n\nThe Weather Loader and Weather Finder applications comprise the weather  subsystem, as shown below:\n\nimage::Weather.png[Weather.png]\n\n===== Weather Loader\n\nThis application loads weather information for geographic locations and runs every five seconds. Infinispan stores that data in the `weather` cache as follows:\n\n- Location: Key `String`\n- Weather: Value `LocationWeather` (temperature, condition, city, country)\n\n===== Weather Finder\n\nThis application uses Infinispan Search capabilities to perform text search and continuous queries.\n\n//Step 1\n=== Starting Infinispan Server\n\nBefore you start coding fun stuff, you need to start Infinispan Server. For\nthis tutorial, you need a locally running server instance.\n\nYou can do one of the following:\n\n* Pull the container image and run with https://www.docker.com/[Docker] or https://podman.io/[Podman].\n* Download the server distribution and extract it to your filesystem.\n\n.Credentials\nBy default, Infinispan Server requires user authentication. This tutorial uses\n`admin` and `secret` credentials but you can use any username and password.\n\n==== Running the Container Image\n\nThe easiest way to run Infinispan Server locally is to pull the container image.\n\n* Podman\n+\n`podman run --net=host -p 11222:11222 -e USER=\"admin\" -e PASS=\"secret\" quay.io/infinispan/server:latest`\n\n* Docker\n+\n`docker run -it -p 11222:11222 -e USER=\"admin\" -e PASS=\"password\" infinispan/server:latest`\n\n==== Running the Server Distribution\n\nInfinispan Server comes as a bare metal distribution that you can run locally.\n\n. Download the server distribution from https://infinispan.org/download/#stable[Infinispan Downloads] and extract it.\n. Open a terminal window in the resulting directory. This is `$ISPN_HOME`.\n. Add credentials.\n+\n[source,bash,options=\"nowrap\"]\n----\n$ ./bin/cli.sh user create admin -p secret\n----\n+\n. Run Infinispan Server.\n+\n[source,bash,options=\"nowrap\"]\n----\n$ ./bin/server.sh\n----\n\n//Step 2\n=== Accessing the Infinispan Console\n\nOpen http://localhost:11222/[http://localhost:11222/] in any browser.\n\nYou'll see the *Welcome to Infinispan Server* page.\n\nimage::welcomeConsole.png[Welcome to the console]\n\nTo start using the Infinispan Console, do the following:\n\n. Select *Go to the console*.\n. Enter your credentials (`admin`/`secret`).\n\n//Step 3\n=== Getting the Weather Application\n\nYou can create the Weather Application yourself going step by step or you can skip ahead and use the complete solution.\n\n\n=== Bootstrap the project\n\nYou'll find the code for each application and placeholder comments for each step in this tutorial on the `main` branch.\n\n```bash\ngit clone -b main https://github.com/infinispan/infinispan-server-tutorial.git\n```\n\n\n=== Use the complete solution\n\nIf you just want to see the Weather System in action, use the completed example on the `solution` branch.\n\n```bash\ngit clone -b solution https://github.com/infinispan/infinispan-server-tutorial.git\n```\n\n[WARNING]\n====\nInfinispan uses Protostream, a Protobuf serialization Java library; Protobuf schemas are generated in build-time.\nYou *must build* the project before running the main classes (even from your editor).\nIf you experience issues with the tests (Docker, running on Mac...), skip the test suite with the\n`-DskipTests=true` flag.\n\n```bash\n# Build\nmvn clean install -DskipTests=true\n\n# Run the loader\nmvn exec:java -Dexec.mainClass=org.infinispan.tutorial.client.temperature.TemperatureLoaderApp\n\n# Run the monitor\nmvn exec:java -Dexec.mainClass=org.infinispan.tutorial.client.temperature.TemperatureMonitorApp\n```\n====\n\n//Step 4\n=== Establishing Remote Connections\n\nConnect to your locally running Infinispan Server from a Hot Rod Java client.\n\n==== Add Dependencies\n\nOpen the `pom.xml` file for this project and confirm that the following dependencies are available:\n\n* `infinispan-client-hotrod` adds the https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html[Java Hot Rod Client].\n* `infinispan-api` adds the Infinispan new API with the annotations.\n* `infinispan-query-dsl` adds the Infinispan Search API.\n* `infinispan-remote-query-client` adds a remote search client.\n\n.pom.xml\n[source,xml]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.infinispan\u003c/groupId\u003e\n    \u003cartifactId\u003einfinispan-client-hotrod\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.infinispan\u003c/groupId\u003e\n    \u003cartifactId\u003einfinispan-api\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.infinispan\u003c/groupId\u003e\n    \u003cartifactId\u003einfinispan-query-dsl\u003c/artifactId\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.infinispan\u003c/groupId\u003e\n    \u003cartifactId\u003einfinispan-remote-query-client\u003c/artifactId\u003e\n\u003c/dependency\u003e\n----\n\n==== Create a Remote Connection\n\nUpdate the `connect()` method in the `DataSourceConnector` class as follows:\n\n.org.infinispan.tutorial.db.DataSourceConnector\n[source,java]\n----\nConfigurationBuilder builder = new ConfigurationBuilder(); //\u003c1\u003e\n\nbuilder.uri(\"hotrod://admin:secret@localhost:11222\"); //\u003c2\u003e\n\nremoteCacheManager = new RemoteCacheManager(builder.build()); //\u003c3\u003e\n----\n\u003c1\u003e Creates a `ConfigurationBuilder`\n\u003c2\u003e HotRod URI connection (server, port and credentials)\n\u003c3\u003e Creates a `RemoteCacheManager` with the configuration.\n\n==== Test the Connection\n\nRun `HealthChecker` to make sure your connection is successful.\n\nYou should see the following messages:\n\n[source,bash]\n----\n\n---- Connect to Infinispan ----\nINFO: ISPN004021: Infinispan version: Infinispan ...\n---- Connection count: 1 ----\n---- Shutdown the client ----\n\n----\n\n//Step 5\n=== Implementing Temperature Loader\n\nIn this section of the tutorial, you implement the Temperature Loader application and learn how to:\n\n- Create caches from the Console.\n- Read data from the cache.\n- Write data to the cache.\n- Expire entries in the cache.\n\n==== Create a Temperature Cache\n\nUpdate the `connect()` method in the `DataSourceConnector` class by adding a `remoteCache(\"temperature\")` as follows:\n\n.org.infinispan.tutorial.db.DataSourceConnector\n[source,java]\n----\nbuilder.remoteCache(\"temperature\").configurationURI(temperatureCacheConfig); \u003c1\u003e\n----\n\u003c1\u003e Adds a cache named `temperature` that uses the content of the 'temperatureCacheConfig.xml' file.\n+\nThis configuration uses Protobuf encoding for keys and values so that you can operate on data from different clients.\n\n[TIP]\n====\nView the configuration in JSON for the cache from the Console once it's created.\n====\n\n==== Put and Read Temperature Data\n\nImplement the `getForLocation()` method in the `TemperatureLoader` service as follows:\n\n.org.infinispan.tutorial.services.temperature.TemperatureLoader\n[source,java]\n----\n   @Override\n   public Float getForLocation(String location) {\n      Float temperature = cache.get(location); //\u003c1\u003e\n      if (temperature == null) {\n         temperature = fetchTemperature(); //\u003c2\u003e\n         cache.put(location, temperature); //\u003c3\u003e\n      }\n      return temperature;\n   }\n\n----\n\u003c1\u003e Get the value for the `location` key.\n\u003c2\u003e Fetches the value if it does not exist in the cache.\n+\nThe private `fetchTemperature()` method emulates an external service call that takes 200ms to retrieve the temperature for a geographic location.\n+\n\u003c3\u003e Adds the value to the `temperature` cache.\n\n==== Verify Temperature Loader\n\nRun `TemperatureLoaderApp` to check that it adds temperature data.\n\nThe first time the application runs, it takes about two seconds to load data. Subsequent calls retrieve the temperature from the cache, which increases performance.\n\nYou should see messages such as the following:\n\n.org.infinispan.tutorial.client.temperature.TemperatureLoaderApp\n[source,java]\n----\n\n---- Connect to Infinispan ----\n\u003ctimestamp\u003e org.infinispan.client.hotrod.RemoteCacheManager actualStart\nINFO: ISPN004021: Infinispan version: Infinispan 'Corona Extra' 11.0.1.Final\n---- Get or create the 'temperature' cache ----\n---- Press any key to quit ----\n---- Loading information ----\nRome, Italy - 22.000622\nComo, Italy - 21.044369\n...\n\n---- Loaded in 1762ms ----\n---- Loading information ----\nRome, Italy - 22.000622\nComo, Italy - 21.044369\n...\n---- Loaded in 44ms ----\nq\n---- Shutdown the client ----\n\n----\n\n==== Expiring Data\n\nAt this point, data in the cache remains the same, even if temperatures at the locations change. You can use expiration to remove data after a period of time so that the Temperature Loader fetches new data for the `temperature` cache.\n\nUpdate the `put()` method in the `TemperatureLoader` class so data expires after 20 seconds as follows:\n\n.org.infinispan.tutorial.services.temperature.TemperatureLoader\n[source,java]\n----\n   cache.put(location, temperature, 20, TimeUnit.SECONDS);\n----\n\nRun the `TemperatureLoaderApp` class again. After 20 seconds you should notice that temperature loading performance decreases because the service needs to fetch data again.\n\n//Step 6\n=== Implementing Temperature Monitor\n\nIn this section of the tutorial, you implement the Temperature Monitor application and learn how to use https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#creating_event_listeners[Infinispan Client Listeners].\n\nThese client listeners enable the Temperator Monitor application to display notifications about temperature changes that happen for each location.\n\n==== Create a Client Listener\n\nAt present, client listeners do not include values of keys in receiving events. For this reason, you use the Async API to get the value and display the temperature that corresponds to the key.\n\nUpdate the `TemperatureMonitor` service as follows:\n\n.org.infinispan.tutorial.services.TemperatureMonitor\n[source,java]\n----\n    @ClientListener //\u003c1\u003e\n    public class TemperatureChangesListener {\n      private String location;\n\n      TemperatureChangesListener(String location) {\n         this.location = location;\n      }\n\n      @ClientCacheEntryCreated //\u003c2\u003e\n      public void created(ClientCacheEntryCreatedEvent event) {\n         if(event.getKey().equals(location)) {\n            cache.getAsync(location) //\u003c3\u003e\n                  .whenComplete((temperature, ex) -\u003e\n                  System.out.printf(\"\u003e\u003e Location %s Temperature %s\", location, temperature));\n         }\n      }\n    }\n\n   ...\n\n    public void monitorLocation(String location) {\n        System.out.println(\"---- Start monitoring temperature changes for \" + location + \" ----\\n\");\n        TemperatureChangesListener temperatureChangesListener = new TemperatureChangesListener(location);\n        cache.addClientListener(temperatureChangesListener); //\u003c4\u003e\n    }\n----\n\u003c1\u003e Annotates `TemperatureChangesListener` with `@ClientListener` to make it an Infinispan Client Listener.\n\u003c2\u003e Uses the `@ClientCacheEntryCreated` annotation to get notifications every time data is added to the `temperature` cache.\n\u003c3\u003e Filters locations by key and gets values using the async call and then prints the new values.\n\u003c4\u003e Adds the client listener to the cache.\n\n[TIP]\n====\nThe preceding example filters events in the listener. However, these events can also be filtered server-side with an https://infinispan.org/docs/stable/titles/hotrod_java/hotrod_java.html#filtering_events[event filter]. However, you must create the filter and deploy it to Infinispan Server, which is beyond the scope of this tutorial.\n====\n\n[IMPORTANT]\n====\nAlways remove client listeners from caches when you no longer need them.\n====\n\n==== Verify Temperature Monitor\n\nMake sure that `TemperatureLoaderApp` is running and then run `TemperatureMonitorApp`.\n\nYou should see a message that displays the current temperature of a location and then get notifications for new temperatures every 20 seconds.\n\n.org.infinispan.tutorial.client.temperature.TemperatureMonitorApp\n[source,bash]\n----\n\n---- Connect to Infinispan ----\n\u003ctimestamp\u003e org.infinispan.client.hotrod.RemoteCacheManager actualStart\nINFO: ISPN004021: Infinispan version: Infinispan 'Corona Extra' 11.0.1.Final\n---- Get or create the 'temperature' cache ----\nTemperature 14.185611 for Bilbao, Spain\n---- Start monitoring temperature changes for Bilbao, Spain ----\n---- Press any key to quit ----\n\u003e\u003e Location Bilbao, Spain Temperature 7.374308\n\u003e\u003e Location Bilbao, Spain Temperature 24.784744\n----\n\n[TIP]\n====\nChange the expiration values to get more notifications. Use `@ClientCacheEntryExpired` to get notifications when data expires.\n====\n\n//Step 7\n=== Implementing Weather Loader\n\nIn this section of the tutorial, you implement the Weather Loader application and learn how to:\n\n- Add complex key/value entries to a cache.\n- Serialize Java objects so they can be transmitted to Infinispan Server.\n- Use https://developers.google.com/protocol-buffers[Protobuf] encoding for searchable data so you perform remote queries from Hot Rod Java clients as well as REST clients and other Hot Rod clients such as C# and Node.js.\n\n==== Annotate the LocationWeather POJO\n\nInfinispan uses https://github.com/infinispan/protostream[Protostream] to serialize data to byte.\n\n* Add the `@Proto` annotation to `LocationWeather`.\n* Add indexing annotations.\n\n.org.infinispan.tutorial.data.LocationWeather\n[source,java]\n----\n@Indexed\n@Proto\npublic record LocationWeather(@Basic\n                              float temperature,\n                              @Basic\n                              String condition,\n                              @Keyword(projectable = true, sortable = true, normalizer = \"lowercase\", indexNullAs = \"unnamed\", norms = false)\n                              String city,\n                              @Keyword(projectable = true, sortable = true, normalizer = \"lowercase\", indexNullAs = \"unnamed\", norms = false)\n                              String country) {\n}\n----\n\n==== Configure the Serialization Context\n\nTo marshall the annotated `LocationWeather` class, Infinispan requires a Protobuf schema. You can either provide a Protobuf descriptor file or create a descriptor file from the annotations you added to the POJO.\n\nIn `LocationWeatherMarshallingContext`, you add the schema to the Protobuf cache in Infinispan and then build a Protobuf using the `@AutoProtoSchemaBuilder` method.\n\n.org.infinispan.tutorial.db.LocationWeatherMarshallingContext\n[source,java]\n----\n@ProtoSchema(\nincludeClasses = {\nLocationWeather.class\n},\nschemaFileName = \"weather.proto\",\nschemaFilePath = \"proto/\",\nschemaPackageName = \"org.infinispan.tutorial.data\")\npublic interface LocationWeatherSchema extends GeneratedSchema {\n}\n----\n\n[IMPORTANT]\n====\nRun `mvn clean package` from the command line or build the project in your IDE to generate the `LocationWeatherSchemaImpl` class.\n====\n\n.org.infinispan.tutorial.db.LocationWeatherMarshallingContext\n[source,java]\n----\n       // Retrieve metadata cache\n      RemoteCache\u003cString, String\u003e metadataCache =\n            cacheManager.getCache(ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME); // \u003c1\u003e\n\n      GeneratedSchema schema = new LocationWeatherSchemaImpl(); // \u003c2\u003e\n\n      // Define the new schema on the server too\n      metadataCache.put(schema.getProtoFileName(), schema.getProtoFile()); //\u003c3\u003e\n----\n\u003c1\u003e Retrieves the metadata cache that stores all Protobuf schemas.\n\u003c2\u003e Use the class generated from the `LocationWeatherSchema` interface to retrieve the schema.\n\u003c3\u003e Adds the schema to the cache.\n\n\n==== Create a Weather Cache\n\nIn this step, you create a `weather` cache that can store `LocationWeather` objects. First you must initialize the marshalling context in the application and then create the cache, as follows:\n\nAs before, configure the `weather` cache.\n\n.org.infinispan.tutorial.db.DataSourceConnector\n[source,java]\n----\nbuilder.remoteCache(\"weather\").configurationURI(weatherCacheConfig); \u003c1\u003e\n----\n\u003c1\u003e Adds a cache named `weather` that uses the content of the 'weatherCacheConfig.xml' file.\n\nUnlike the `temperature` cache, the `weather` cache stores complex Java objects and you will query\nthe values. For this reason the serialization context needs to be registered on the client\nand on Infinispan Server.\n\n.org.infinispan.tutorial.db.DataSourceConnector\n[source,java]\n----\n=     public RemoteCache\u003cString, LocationWeather\u003e getWeatherCache() {\n        System.out.println(\"--- Get or Create a queryable weather cache ---\");\n        Objects.requireNonNull(remoteCacheManager);\n\n        LocationWeatherMarshallingContext.initSerializationContext(remoteCacheManager); // \u003c1\u003e\n\n        return remoteCacheManager.getCache(\"weather\"); // \u003c2\u003e\n    }\n----\n\u003c1\u003e Initializes the serialization context.\n\u003c2\u003e Gets the `weather` cache.\n\n==== Verify Weather Loader\n\nThe code that loads data into the `weather` cache is located in the `org.infinispan.tutorial.services.weather.FullWeatherLoader`. Because this service is similar to the code you implemented for the `TemperatureLoader` service, you don't need to do anything else.\n\nRun `WeatherLoaderApp` to check that it loads weather data.\n\nYou should see messages that indicate the `weather` cache is created and weather information is added for different locations:\n\n.org.infinispan.tutorial.client.weather.WeatherLoaderApp\n[source,bash]\n----\n\n---- Connect to Infinispan ----\n\u003ctimestamp\u003e org.infinispan.client.hotrod.RemoteCacheManager actualStart\nINFO: ISPN004021: Infinispan version: Infinispan 'Corona Extra' 11.0.1.Final\nLocationWeatherMarshallingContext - initialize the serialization context for LocationWeather class\n---- Get or create the 'weather' cache ----\n---- Press any key to quit ----\n\n---- Loading information ----\nRome, Italy - LocationWeather{temperature=17.252243, condition='SUNNY', city='Rome', country='Italy'}\nComo, Italy - LocationWeather{temperature=24.495003, condition='WINDLESS', city='Como', country='Italy'}\nBasel, Switzerland - LocationWeather{temperature=19.795946, condition='WINDLESS', city='Basel', country='Switzerland'}\nBern, Switzerland - LocationWeather{temperature=20.455978, condition='WINDLESS', city='Bern', country='Switzerland'}\n...\n---- Loaded in 3386ms ----\n\n---- Loading information ----\nRome, Italy - LocationWeather{temperature=17.252243, condition='CLOUDY', city='Rome', country='Italy'}\nComo, Italy - LocationWeather{temperature=24.495003, condition='PARTIALLY_COVERED', city='Como', country='Italy'}\n...\n---- Loaded in 70ms ----\n\n----\n\n//Step 8\n=== Implementing Weather Finder\n\nIn this section of the tutorial, you learn how to:\n\n* Create and run FROM queries.\n* Create and run SELECT queries.\n* Perform continuous queries.\n\n==== Create a FROM Query\n\nCreate a FROM query on values in the `weather` cache as follows:\n\n.org.infinispan.tutorial.services.weather.WeatherSearch\n[source,java]\n----\n   public List\u003cLocationWeather\u003e findByCountry(String country) {\n      // Use Ickle to run the query\n      Query\u003cLocationWeather\u003e query = weather.query(\"FROM org.infinispan.tutorial.data.LocationWeather WHERE country = :country\"); //\u003c1\u003e\n\n      // Set the parameter value\n      query.setParameter(\"country\", country); //\u003c2\u003e\n\n      return query.execute().list(); // \u003c3\u003e\n   }\n----\n\u003c1\u003e Creates a FROM query using the Ickle query language. This query finds each `LocationWeather` in a country.\n\u003c2\u003e Sets the `country` parameter.\n\u003c3\u003e Executes the query and returns the list.\n\n==== Run the FROM Query\n\nMake sure `WeatherLoaderApp` is running and then run `WeatherFinderApp`.\n\nYou should see output such as the following:\n\n.org.infinispan.tutorial.client.weather.WeatherFinderApp\n[source,bash]\n----\n---- Get or create the 'weather' cache ----\nSpain: [LocationWeather{temperature=6.2846804, condition='CLOUDY',city='Bilbao', country='Spain'},\nLocationWeather{temperature=18.044653, condition='SUNNY', city='Madrid', country='Spain'}]\n----\n\n==== Create a SELECT Query\n\nFor some queries, you don't want every field for an object. In this example, you create and run a query that returns only the `city` that matches a given weather condition.\n\n.org.infinispan.tutorial.services.weather.WeatherSearch\n[source,java]\n----\n    public List\u003cString\u003e findByCondition(WeatherCondition condition) {\n      Query\u003cObject[]\u003e query = createFindLocationWeatherByConditionQuery(condition);\n      return query.execute().list().stream().map(data -\u003e (String) data[0]).collect(Collectors.toList()); //\u003c3\u003e\n    }\n\n    private Query\u003cObject[]\u003e createFindLocationWeatherByConditionQuery(WeatherCondition condition) {\n      // Use Ickle to run the query\n      Query\u003cObject[]\u003e query = weather.query(\"SELECT city FROM org.infinispan.tutorial.data.LocationWeather WHERE condition = :condition\"); // \u003c1\u003e\n\n      // Set the parameter value\n      query.setParameter(\"condition\", condition.name()); //\u003c2\u003e\n\n      return query;\n   }\n----\n\n\u003c1\u003e Creates a SELECT query using the Ickle query language. This query finds every `LocationWeather` with a weather condition and returns only the city.\n\u003c2\u003e Sets the `condition` parameter.\n\u003c3\u003e Executes the query, returns the list, and filters the `Object[]` to get the `String` results.\n\n==== Run the SELECT Query\n\nMake sure `WeatherLoaderApp` is running and then run `WeatherFinderApp`.\n\nYou should see output such as the following:\n\n.org.infinispan.tutorial.client.weather.WeatherFinderApp\n[source,bash]\n----\nSUNNY: [Madrid]\nCLOUDY: [Lisbon, Bilbao, Newcastle, Como]\nRAINY: [Cluj-Napoca]\nPARTIALLY_COVERED: [Toronto, Bern]\nHUMID: []\nWINDY: []\nFOGGY: [Washington, Porto, Rome]\nWINDLESS: [London, Raleigh]\nDRY: [Ottawa]\nWET: [Basel, Bucarest]\n----\n\n==== Create a Continuous Query\n\nhttps://infinispan.org/docs/stable/titles/developing/developing.html#query_continuous[Continuous Queries] allow applications to register listeners that receive the entries matching a query filter. In this way, applications are continuously notified of changes to the queried data set.\n\n.org.infinispan.tutorial.services.weather.WeatherSearch\n[source,java]\n----\npublic void findWeatherByConditionContinuously(WeatherCondition condition) {\n      Query\u003cObject[]\u003e query = createFindLocationWeatherByConditionQuery(condition); //\u003c1\u003e\n      ContinuousQuery\u003cString, LocationWeather\u003e continuousQuery = weather.continuousQuery(); //\u003c2\u003e\n\n      // Create the continuous query listener.\n      ContinuousQueryListener\u003cString, Object[]\u003e listener = //\u003c3\u003e\n            new ContinuousQueryListener\u003c\u003e() {\n               // This method will be executed every time new items that correspond with the query arrive\n               @Override\n               public void resultJoining(String key, Object[] data) {\n                  System.out.printf(\"%s is now %s%n\", data[0], condition);\n               }\n            };\n\n      // And the listener corresponding the query to the continuous query\n      continuousQuery.addContinuousQueryListener(query, listener); //\u003c4\u003e\n   }\n----\n\n\u003c1\u003e Creates a query that finds all locations with a certain weather condition; for example, 'Sunny'.\n\u003c2\u003e Creates a continuous query on the `weather` cache.\n\u003c3\u003e Creates a continuous query listener and prints the condition.\n\u003c4\u003e Matches the query and the listener in the `ContinuousQuery` object\n\n[IMPORTANT]\n====\nAlways remove continuous queries when you no longer need them.\n====\n\n==== Run the Continuous Query\n\nMake sure `WeatherLoaderApp` is running and then run `WeatherFinderApp`.\n\nYou should see output such as the following:\n\n.org.infinispan.tutorial.client.weather.WeatherFinderApp\n[source,bash]\n----\n---- Press any key to quit ----\nMadrid is now SUNNY\nBilbao is now SUNNY\nToronto is now SUNNY\nNewcastle is now SUNNY\nCluj-Napoca is now SUNNY\nPorto is now SUNNY\n...\n----\n\n//Step 9\n=== Testing Infinispan Server\n\nhttps://www.testcontainers.org/test_framework_integration/junit_5/[Test containers] are a great way to run an Infinispan Server and test with a https://junit.org/junit5/[Junit 5] extension.\n\nThis section of the tutorial provides an example test that verifies the temperatures loaded in Infinispan Server are correct.\n\n[IMPORTAT]\n====\nYou need https://www.docker.com/[Docker] for this part of the tutorial.\n====\n\n==== Add Dependencies\n\nOpen the `pom.xml` file for this project and add the `infinispan-server-testdriver-junit5` dependency as follows:\n\n\n.pom.xml\n[source,xml]\n----\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.infinispan\u003c/groupId\u003e\n        \u003cartifactId\u003einfinispan-server-testdriver-junit5\u003c/artifactId\u003e\n        \u003cversion\u003e${version.infinispan}\u003c/version\u003e\n        \u003cscope\u003etest\u003c/scope\u003e\n    \u003c/dependency\u003e\n----\n\n[NOTE]\n====\nJUnit 4 rules are also available for out-of-the-box testing with Infinispan Server. Check the `infinispan-server-testdriver-junit4` dependency.\n====\n\n==== Using Test Containers\n\nCreate a Junit 5 Test and use the `InfinispanServerExtension`.\n\n.org.infinispan.tutorial.services.temperature.TemperatureLoaderTest\n[source,java]\n----\n\n   @RegisterExtension\n   static InfinispanServerExtension infinispanServerExtension = InfinispanServerExtensionBuilder.server(); // \u003c1\u003e\n\n   @Test\n   public void loadLocationTemperature() {\n      DataSourceConnector dataSourceConnector = new DataSourceConnector(createRemoteCacheManager());\n      TemperatureLoader temperatureLoader = new TemperatureLoader(dataSourceConnector);\n      Float temperatureLoaderForLocation = temperatureLoader.getForLocation(WeatherLoader.LOCATIONS[0]);\n      assertNotNull(temperatureLoaderForLocation);\n   }\n\n   // \u003c2\u003e\n   private RemoteCacheManager createRemoteCacheManager() {\n      RemoteCacheManager remoteCacheManager = infinispanServerExtension.hotrod().createRemoteCacheManager();\n      SerializationContext serCtx = MarshallerUtil.getSerializationContext(remoteCacheManager);\n      LocationWeatherSchema schema = new LocationWeatherSchemaImpl();\n      schema.registerSchema(serCtx);\n      schema.registerMarshallers(serCtx);\n      return remoteCacheManager;\n   }\n----\n\n\u003c1\u003e Registers the Junit 5 Infinispan Server Extension.\n\u003c2\u003e Adds a serialization context for the tests.\n\n== What's Next?\n\nCongratulations on completing this tutorial!\n\nYou should now be well on your way with using the Infinispan Server. Here are some more things to help you keep learning:\n\n.Infinispan Integrations\n\nhttps://quarkus.io/[Quarkus], https://infinispan.org/infinispan-spring-boot/master/spring_boot_starter.html[Spring Boot], https://vertx.io/[Vert.x] and other frameworks are featured in the https://github.com/infinispan-demos[Infinispan demos].\n\n.Kubernetes Operator\n\nVisit the https://infinispan.org/infinispan-operator/master/operator.html[Infinispan Operator Guide] and learn how to deploy and scale Infinispan on https://kubernetes.io[Kubernetes] or https://www.openshift.com/[OpenShift].\n\n.Remote Clients\n\nTry the https://infinispan.org/docs/stable/titles/rest/rest.html[Infinispan REST API] and check out different https://infinispan.org/hotrod-clients/[Hot Rod clients] to use Infinispan with other programming languages.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfinispan%2Finfinispan-server-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfinispan%2Finfinispan-server-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfinispan%2Finfinispan-server-tutorial/lists"}