{"id":18429132,"url":"https://github.com/openliberty/guide-sessions","last_synced_at":"2025-04-07T17:32:47.459Z","repository":{"id":34008508,"uuid":"138199500","full_name":"OpenLiberty/guide-sessions","owner":"OpenLiberty","description":"A guide on how to create, use, and cache HTTP session data for your application: ","archived":false,"fork":false,"pushed_at":"2025-03-05T20:13:07.000Z","size":15239,"stargazers_count":4,"open_issues_count":2,"forks_count":12,"subscribers_count":4,"default_branch":"prod","last_synced_at":"2025-03-22T21:51:09.641Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://openliberty.io/guides/sessions.html","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenLiberty.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":"CONTRIBUTING.md","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":"2018-06-21T17:05:03.000Z","updated_at":"2025-03-05T20:13:14.000Z","dependencies_parsed_at":"2024-02-20T18:29:23.406Z","dependency_job_id":"22ff8f0d-4e22-41aa-8bba-9be1218b5c4a","html_url":"https://github.com/OpenLiberty/guide-sessions","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenLiberty%2Fguide-sessions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenLiberty%2Fguide-sessions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenLiberty%2Fguide-sessions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenLiberty%2Fguide-sessions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenLiberty","download_url":"https://codeload.github.com/OpenLiberty/guide-sessions/tar.gz/refs/heads/prod","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247697945,"owners_count":20981277,"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":[],"created_at":"2024-11-06T05:15:58.011Z","updated_at":"2025-04-07T17:32:47.137Z","avatar_url":"https://github.com/OpenLiberty.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"// Copyright (c) 2019, 2024 IBM Corporation and others.\n// Licensed under Creative Commons Attribution-NoDerivatives\n// 4.0 International (CC BY-ND 4.0)\n//   https://creativecommons.org/licenses/by-nd/4.0/\n//\n// Contributors:\n//     IBM Corporation\n//\n:page-layout: guide-multipane\n:projectid: sessions\n:page-duration: 25 minutes\n:page-releasedate: 2019-07-23\n:page-description: Learn how to create, use and cache HTTP session data.\n:guide-author: Open Liberty\n:page-tags: ['docker']\n:page-related-guides: ['rest-intro', 'microprofile-openapi', 'kubernetes-intro']\n:page-permalink: /guides/{projectid}\n:common-includes: https://raw.githubusercontent.com/OpenLiberty/guides-common/prod\n:imagesdir: /img/guide/{projectid}\n:page-seo-title: Caching HTTP session data using JCache and Hazelcast\n:page-seo-description: A getting started tutorial with examples on how to create, use, and cache HTTP session data for an enterprise Java application on a Kubernetes cluster by using Java Caching (JCache).\n= Caching HTTP session data using JCache and Hazelcast\n\nLearn how to create, use, and cache HTTP session data for your application.\n\n:kube: Kubernetes\n:win: WINDOWS\n:mac: MAC\n:linux: LINUX\n\n// =================================================================================================\n// Introduction\n// =================================================================================================\n== What you'll learn\n\n=== What is a session?\n// *Session* +\nOn the internet, a web server doesn't know who you are or what you do\nbecause it's processing stateless HTTP requests. An HTTP session provides a way to store\ninformation to be used across multiple requests.\nSession variables store user information like user name or items in a shopping cart.\nBy default, session variables will timeout after 30 minutes of being unused.\nCookies, which also store user information, are maintained on a client's computer,\nwhereas session variables are maintained on a web server. For security reasons,\nan HTTP session is preferred over cookies when used with sensitive data.\nA session hides data from users.\nCookies can be manipulated by a savvy user to make fake requests to your site.\n\n=== What is session persistence?\n// *Session caching* +\nHigh traffic websites must support thousands of users in a fast and reliable way.\nLoad balancing requires running several instances of the same application in parallel\nso that traffic can be routed to different instances to maximize speed and reliability.\nUnless a user is tied to a particular instance, running multiple instances of the same\napplication can pose an out-of-sync problem when each instance keeps an isolated copy of its\nsession data. HTTP session data caching can solve this problem by allowing all\ninstances of the application to share caches among each other.\nSharing caches among instances eliminates the need to route a user to the same instance\nand helps in failover situations by distributing the cache.\n\nimage::sessionCache.png[Session Cache,width=100%]\n\nYou will learn how to build an application that creates and uses HTTP session data.\nYou will also learn how to use Open Liberty's `sessionCache` feature to persist HTTP sessions\nby using Java Caching (JCache), the standard caching API for Java.\n\nYou will containerize and deploy the application to a local Kubernetes cluster.\nYou will then replicate the application in multiple pods and see that the session data is cached and\nshared among all instances of the application. Even if an instance is unavailable, the other instances\nare able to take over and handle requests from the same user by using the cached session data.\n\n\n// =================================================================================================\n// Prerequisites\n// =================================================================================================\n[role='command']\ninclude::{common-includes}/kube-prereq.adoc[]\n\n// =================================================================================================\n// Getting Started\n// =================================================================================================\n[role=\"command\"]\ninclude::{common-includes}/gitclone.adoc[]\n\n\n== Creating the application\n\nThe application that you are working with is a shopping cart web service that uses JAX-RS,\nwhich is a Java API for building RESTful web services.\nYou'll learn how to persist a user's shopping cart data between Open Liberty instances by using the\n`sessionCache` feature. The `sessionCache` feature persists HTTP\nsessions using JCache. You can have high-performance HTTP session persistence\nwithout using a relational database.\n\nNavigate to the `start` directory to begin.\n\n[role=\"code_command hotspot file=0\", subs=\"quotes\"]\n----\n#Create the `CartApplication` class.#\n`src/main/java/io/openliberty/guides/cart/CartApplication.java`\n----\nCartApplication.java\n[source, Java, linenums, indent=0, role=\"code_column hide_tags=copyright\"]\n----\ninclude::finish/src/main/java/io/openliberty/guides/cart/CartApplication.java[]\n----\n\nThe [hotspot file=0]`CartApplication` class extends the generic JAX-RS application class that is needed to run the\napplication.\n\n[role=\"code_command hotspot file=1\", subs=\"quotes\"]\n----\n#Create the `CartResource` class.#\n`src/main/java/io/openliberty/guides/cart/CartResource.java`\n----\nCartResource.java\n[source, Java, linenums, indent=0, role=\"code_column hide_tags=copyright\"]\n----\ninclude::finish/src/main/java/io/openliberty/guides/cart/CartResource.java[]\n----\n\nThe [hotspot file=1]`CartResource` class defines the REST endpoints at which a user can make\nan HTTP request.\n\nThe [hotspot=addToCart file=1]`addToCart` and [hotspot=getCart file=1]`getCart` methods\nhave a number of annotations. Most of these annotations are used by the\nMicroProfile OpenAPI and JAX-RS features to document the REST endpoints and map Java objects to web resources.\nMore information about these annotations can be found in the\nhttps://openliberty.io/guides/microprofile-openapi.html#augmenting-the-existing-jax-rs-annotations-with-openapi-annotations[Documenting RESTful APIs^]\nand\nhttps://openliberty.io/guides/rest-intro.html#creating-a-jax-rs-application[Creating a RESTful web service^]\nguides.\n\nThe [hotspot=endpointCartItemPrice file=1]`cart/{item}\u0026{price}` endpoint demonstrates how to set session data.\nThe [hotspot=item hotspot=price file=1]`@PathParam` annotation injects a custom [hotspot=item file=1]`item` and\n[hotspot=price file=1]`price` from the POST request into the method parameter.\nThe [hotspot=addToCart file=1]`addToCart` method gets the current [hotspot=getSession file=1]`session` and binds\nthe `{item}:{price}` key-value pair into the session by the [hotspot=setAttribute file=1]`setAttribute()` method.\nA response is then built and returned to confirm that an item was added to your cart and session.\n\nThe [hotspot=endpointCart file=1]`cart` endpoint demonstrates how to get session data.\nThe [hotspot=getCart file=1]`getCart` method gets the current session, iterates through all key-value\npairs that are stored in the current session, and creates a `JsonObject` response.\nThe `JsonObject` response is returned to confirm the Liberty instance by\n[hotspot=podname file=1]`pod-name`, the session by [hotspot=sessionid file=1]`session-id`,\nand the items in your cart by [hotspot=cart file=1]`cart`.\n\n\n== Configuring session persistence\n\n=== Using client-server vs peer-to-peer model\n\nSession caching is only valuable when a server is connected to at least\none other member. There are two different ways session caching can behave in a\ncluster environment:\n\n* Client-server model: A Liberty instance can act as the JCache client and connect\nto a dedicated JCache server.\n* Peer-to-peer model: A Liberty instance can connect with other Liberty instances\nthat are also running with the session cache and configured to be\npart of the same cluster.\n\nYou'll use the peer-to-peer model in a Kubernetes environment for this guide.\n\n=== Configuring session persistence with JCache in Open Liberty\n\nJCache, which stands for Java Caching, is an interface\nto standardize distributed caching on the Java platform.\nThe [hotspot=sessionCache]`sessionCache` feature uses JCache, which allows for session\npersistence by providing a common cache of session data between Liberty instances.\nThis feature doesn't include a JCache implementation.\nFor this guide, you'll use Hazelcast as an open source JCache provider.\n\nHazelcast is a JCache provider. Open Liberty needs to be configured to use\nHazelcast after the [hotspot=sessionCache]`sessionCache` feature is enabled.\n\n[role=\"code_command hotspot\", subs=\"quotes\"]\n----\n#Create the Liberty `server.xml` configuration file.#\n`src/main/liberty/config/server.xml`\n----\n\nserver.xml\n[source, xml, linenums, indent=0, role=\"code_column hide_tags=copyright\"]\n----\ninclude::finish/src/main/liberty/config/server.xml[]\n----\n\npom.xml\n[source, xml, linenums, indent=0, role=\"code_column hide_tags=copyright\"]\n----\ninclude::finish/pom.xml[]\n----\n\nThe [hotspot=library file=0]`library` element includes the library reference that indicates\nto the Liberty where the Hazelcast implementation of JCache is located. \nYour Hazelcast implementation of JCache is a JAR file that resides in the shared resources directory that is defined by the [hotspot=hazelcastjar file=0]`file` element.\nThe `hazelcast-*.jar` file is downloaded by the Liberty Maven plugin. The [hotspot=configuration file=1]`configuration` is defined in the provided Maven POM file.\n\n=== Configuring Hazelcast\n\nserver.xml\n[source, xml, linenums, indent=0, role=\"code_column hide_tags=copyright\"]\n----\ninclude::finish/src/main/liberty/config/server.xml[]\n----\n\nBy default, all Open Liberty instances that run the [hotspot=sessionCache file=0]`sessionCache`\nfeature and Hazelcast are connected using a peer-to-peer model.\n\nYou can share the session cache only among certain Hazelcast instances\nby using the `cluster-name` configuration element in the Hazelcast configuration file.\n\n[role=\"code_command hotspot file=1\", subs=\"quotes\"]\n----\n#Create the `hazelcast-config.xml` configuration file.#\n`src/main/liberty/config/hazelcast-config.xml`\n----\n\nhazelcast-config.xml\n[source, xml, linenums, indent=0, role=\"code_column hide_tags=copyright\"]\n----\ninclude::finish/src/main/liberty/config/hazelcast-config.xml[]\n----\n\nThe [hotspot=cartCluster file=1]`CartCluster` cluster name is defined in the [hotspot file=1]`hazelcast-config.xml` file. To allow Hazelcast cluster members to find each other, enable the [hotspot=multicast file=1]`multicast` communication in the [hotspot=network file=1]`network` configuration.\n\nIn the [hotspot file=0]`server.xml` configuration file, a reference to the Hazelcast configuration file is made by using\nthe [hotspot=httpSessionCache file=0]`httpSessionCache` tag.\n\n\n[role=\"code_command hotspot file=2\", subs=\"quotes\"]\n----\n#Create the `bootstrap.properties` file.#\n`src/main/liberty/config/bootstrap.properties`\n----\n\nbootstrap.properties\n[source, text, linenums, indent=0, role=\"code_column\"]\n----\ninclude::finish/src/main/liberty/config/bootstrap.properties[]\n----\n\nHazelcast JCache provides the client and member providers. Set `hazelcast.jcache.provider.type` to `member` to use the member provider.\n\nThere are more configuration settings that you can explore in the\nhttps://docs.hazelcast.org/docs/latest/manual/html-single/#understanding-configuration[Hazelcast documentation^].\n\n// =================================================================================================\n// Running the application\n// =================================================================================================\n\n== Running the application\n\n[role=\"command\"]\ninclude::{common-includes}/devmode-lmp33-start.adoc[]\n\nPoint your browser to the link:http://localhost:9090/openapi/ui/[^] URL.\nThis URL displays the available REST endpoints.\n\nFirst, make a POST request to the `/cart/{item}\u0026{price}` endpoint. To make this request, expand the POST\nendpoint on the UI, click the `Try it out` button, provide an item and a price,\nand then click the `Execute` button.\nThe POST request adds a user-specified item and price to a session\nthat represents data in a user's cart.\n\nNext, make a GET request to the `/cart` endpoint. To make this request, expand the GET\nendpoint on the UI, click the `Try it out` button,\nand then click the `Execute` button. The GET request\nreturns a pod name, a session ID, and all the items from your session.\n\n[role='command']\ninclude::{common-includes}/devmode-quit-ctrlc.adoc[]\n\n// =================================================================================================\n// Staring and preparing your cluster for deployment\n// =================================================================================================\n[role='command']\ninclude::{common-includes}/kube-start.adoc[]\n\n\n== Containerizing the application\n\nBefore you can deploy the application to Kubernetes, you need to containerize it with Docker.\n\nMake sure to start your Docker daemon before you proceed.\n\nThe Dockerfile is provided at the `start` directory. If you're unfamiliar with Dockerfile,\ncheck out the https://openliberty.io/guides/containerize.html[Containerizing microservices^] guide,\nwhich covers Dockerfile in depth.\n\nRun the `mvn package` command from the `start` directory so that the `.war` file resides in the `target` directory.\n\n[role='command']\n```\nmvn package\n```\n\n\n\nTo build and containerize the application, run the following Docker build command in the `start` directory:\n\n[role='command']\n```\ndocker build -t cart-app:1.0-SNAPSHOT .\n```\n\nWhen the build finishes, run the following command to list all local Docker images:\n[role='command']\n```\ndocker images\n```\n\nVerify that the `cart-app:1.0-SNAPSHOT` image is listed among the Docker images, for example:\n[source, role=\"no_copy\"]\n----\nREPOSITORY                     TAG\ncart-app                       1.0-SNAPSHOT\nicr.io/appcafe/open-liberty    kernel-slim-java11-openj9-ubi\n----\n\n\n== Deploying and running the application in Kubernetes\n\nkubernetes.yaml\n[source, yaml, linenums, role='code_column']\n----\ninclude::finish/kubernetes.yaml[]\n----\n\nNow that the containerized application is built, deploy it to a local Kubernetes cluster by using\na Kubernetes resource definition, which is provided in the [hotspot file=0]`kubernetes.yaml` file\nat the `start` directory.\n\nFirst, use the `ClusterRoleBinding` Kubernetes API object to grant Hazelcast members to access the cluster.\n[role='command']\n```\nkubectl apply -f https://raw.githubusercontent.com/hazelcast/hazelcast/master/kubernetes-rbac.yaml\n```\n\nRun the following command to deploy the application into [hotspot=replicas file=0]`3` replicated pods as defined\nin the `kubernetes.yaml` file:\n[role='command']\n```\nkubectl apply -f kubernetes.yaml\n```\n\nWhen the application is deployed, run the following command to check the status of your pods:\n[role='command']\n```\nkubectl get pods\n```\n\nYou see an output similar to the following if all the pods are working correctly:\n\n[role=\"no_copy\"]\n----\nNAME                             READY  STATUS   RESTARTS  AGE\ncart-deployment-98f4ff789-2xlhs  1/1    Running  0         17s\ncart-deployment-98f4ff789-6rvfj  1/1    Running  0         17s\ncart-deployment-98f4ff789-qrh45  1/1    Running  0         17s\n----\n\n\ninclude::{common-includes}/os-tabs.adoc[]\n\n[.tab_content.windows_section.mac_section]\n--\nPoint your browser to the link:http://localhost:31000/openapi/ui/[^] URL.\nThis URL displays the available REST endpoints.\n--\n\n[.tab_content.linux_section]\n--\nRun the `minikube ip` command to get the hostname for minikube.\nThen, go to the `http://[hostname]:31000/openapi/ui/` URL in your browser. \nThis URL displays the available REST endpoints.\n--\n\nMake a POST request to the `/cart/{item}\u0026{price}` endpoint. To make this request, expand the POST\nendpoint on the UI, click the `Try it out` button, provide an item and a price,\nand then click the `Execute` button.\nThe POST request adds a user-specified item and price to a session\nthat represents data in a user's cart.\n\nNext, make a GET request to the `/cart` endpoint. To make this request, expand the GET\nendpoint on the UI, click the `Try it out` button, and then click the `Execute` button.\nThe GET request returns a pod name, a session ID, and all the items from your session.\n\n[role=\"no_copy\"]\n----\n{\n  \"pod-name\": \"cart-deployment-98f4ff789-2xlhs\",\n  \"session-id\": \"RyJKzmka6Yc-ZCMzEA8-uPq\",\n  \"cart\": [\n    \"eggs | $2.89\"\n  ],\n  \"subtotal\": 2.89\n}\n----\n\nReplace the `[pod-name]` in the following command, and then run the command to pause\nthe pod for the GET request that you just ran:\n\n[role='command']\n```\nkubectl exec -it [pod-name] -- /opt/ol/wlp/bin/server pause\n```\n\nRepeat the GET request. You see the same `session-id`\nbut a different `pod-name` because the session data is cached but the request\nis served by a different pod (Liberty instance).\n\nVerify that the Hazelcast cluster is running by checking the Open Liberty log. \nTo check the log, run the following command:\n\n[role='command']\n```\nkubectl exec -it [pod-name] -- cat /logs/messages.log\n```\n\nYou see a message similar to the following:\n\n[role=\"no_copy\"]\n----\n... [10.1.0.46]:5701 [CartCluster] [5.3.0]\n\nMembers {size:3, ver:3} [\n\tMember [10.1.0.40]:5701 - 01227d80-501e-4789-ae9d-6fb348d794ea\n\tMember [10.1.0.41]:5701 - a68d0ed1-f50e-4a4c-82b0-389f356b8c73 this\n\tMember [10.1.0.42]:5701 - b0dfa05a-c110-45ed-9424-adb1b2896a3d\n]\n----\n\nYou can resume the paused pod by running the following command:\n\n[role='command']\n```\nkubectl exec -it [pod-name] -- /opt/ol/wlp/bin/server resume\n```\n\n\n// =================================================================================================\n// Tear Down\n// =================================================================================================\n\n== Tearing down the environment\n\nWhen you no longer need your deployed application, you can delete all {kube} resources and disable the Hazelcast members' access to the cluster by running the `kubectl delete` commands:\n\n[role='command']\n```\nkubectl delete -f kubernetes.yaml\nkubectl delete -f https://raw.githubusercontent.com/hazelcast/hazelcast/master/kubernetes-rbac.yaml\n```\n\n[role='command']\ninclude::{common-includes}/kube-minikube-teardown.adoc[]\n\n\n== Great work! You're done!\n\nYou have created, used, and cached HTTP session data for an application that was running on Open Liberty\nand deployed in a Kubernetes cluster.\n\n\ninclude::{common-includes}/attribution.adoc[subs=\"attributes\"]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenliberty%2Fguide-sessions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenliberty%2Fguide-sessions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenliberty%2Fguide-sessions/lists"}