Learn how to create and work with session data that persists between servers using the sessionCache feature in Open Liberty.
You’ll learn about session and session persistence theory. You’ll also learn how to set
and get session data in microservices. For security reasons, using
sessions is preferred over using cookies for sensitive data. Sessions hide data
from users. Cookies store data on the client’s computer, and can be manipulated by a
savvy user to make fake requests to your site.
The microservice that you’ll be working with is a shopping cart web service. You’ll
learn how to persist a user’s shopping cart data between servers using
the sessionCache feature in Open Liberty.
The sessionCache feature persists HTTP sessions using Java Caching (JCache).
You can have high performance HTTP session persistence without the use of a
relational database. Furthermore, failover of HTTP sessions can be achieved by
configuring multiple servers to persist data to the
same location.
A session is a way to store information to be used across multiple pages.
When you work with a local application (such as a word processor), you open it,
make changes, and then you close it. The computer knows that you opened the app,
made changes, and closed the app. On the internet, however, the web server doesn’t
know who you are, or what you do, because it’s just processing stateless HTTP
requests. Session variables store user information like user names or items in a cart.
By default, session variables will time out after 30 minutes of being unused.
Session variables are maintained on a web server. Cookies, which also store user
information, are maintained on a client’s computer.
The primary use case of session persistence is to be able to handle client requests
being routed to different backends or to handle failover of the backend system.
High traffic websites must support thousands of users in a fast and reliable way.
Load balancing requires running several instances of the same service in parallel
so that traffic can be routed to servers to maximize speed and reliability.
This poses a problem when each server keeps an isolated copy of their session data.
In this case, a user is tied to a particular server, and if that server fails
then that server’s session data will be lost.
Session persistence using a session cache, as illustrated, solves this
problem by allowing all server instances to share caches among each other. This
eliminates the need to always route a user to the same server instance, and also
helps in failover situations by distributing the cache.
The finish directory in the root of this guide contains the finished application.
Give it a try before you proceed.
To try out the application, first navigate to the finish directory and then run
the following Maven goal to build the application and run it inside Open Liberty:
mvn install liberty:start-server -DserverName=server1Point your browser to the http://localhost:9080/openapi/ui/ URL. This will
display the available REST endpoints on the server1 server.
First, make a POST request to /cart/{item}&{price}.
The POST request will add a user specified item and price to a session
that represents data in a user’s cart.
Then, make a GET request to /cart. The GET request
will return all the items from your session and display it as a string.
After you’re done checking out the application, stop the Open Liberty server.
mvn liberty:stop-server -DserverName=server1You’ll create a cart microservice to store and retrieve session data.
Navigate to the start directory to begin.
Create theCartApplicationclass.src/main/java/io/openliberty/guides/cart/CartApplication.java
CartApplication.java
link:finish/src/main/java/io/openliberty/guides/cart/CartApplication.java[role=include]The CartApplication class extends the generic JAX-RS application class needed to run the
application.
Create theCartResourceclass.src/main/java/io/openliberty/guides/cart/CartResource.java
CartResource.java
link:finish/src/main/java/io/openliberty/guides/cart/CartResource.java[role=include]The CartResource class defines the REST endpoints at which a user can make
an HTTP request.
The addToCart and getCart methods
have a number of annotations most of which
are used by the myOpenAPI and jaxrs features to provide context to
the user interface and map java objects to web resources.
More information about these annotations can be found in the
Documenting RESTful APIs
and
Creating a RESTful web service
guides.
The @PathParam annotation injects a custom
item and price from the POST
request into the method parameter.
The addToCart method gets the current session and sets a new attribute
stored as the key-value pair {item}:{price}. A response is then built and
returned to confirm that an item has been added to your cart or session.
The getCart method will get the current session. Iterate through all key-value
pairs stored in the current session and create a String response that is returned
to confirm the value of the item(s) in your cart or session.
The sessionCache feature is only valuable when it’s connected to at least
one other member. There are two different ways session caching can behave in a
server environment:
-
Client-Server Model: A Liberty server can act as the JCache client and connect to a dedicated JCache server.
-
Peer-to-Peer Model: A Liberty server can connect with other Liberty servers that are also running with the
sessionCachefeature and configured to be part of the same cluster.
You’ll use the peer-to-peer model for this guide.
JCache stands for Java Caching and is an interface
to standardize distributed caching on the Java platform.
The sessionCache feature makes use of JCache which allows for session
persistence by providing a common cache of session data between servers.
This feature doesn’t include a JCache implementation.
For this guide, you’ll use Hazelcast as an open source JCache provider.
Hazelcast is a JCache provider. Open Liberty needs to be configured to use
HazelCast once the sessionCache feature is enabled.
Create theserver.xmlconfig file.src/main/liberty/config/server.xml
server.xml
link:finish/src/main/liberty/config/server.xml[role=include]The library tag lets the server know where the Hazelcast implementation of
JCache is located by including a library reference. When the maven build is run
the hazelcast.jar file is downloaded as a dependency and then copied to the
predefined {shared.resource.dir} directory.
CartApplication.java
link:finish/src/main/java/io/openliberty/guides/cart/CartApplication.java[role=include]server.xml
link:finish/src/main/liberty/config/server.xml[role=include]By default, all Open Liberty servers running sessionCache,
the CartApplication you have created,
and Hazelcast will be connected using a peer-to-peer model.
You can limit the Hazelcast instances that have access to session data by making them join a cluster with the correct username and password. This is accomplished by creating a Hazelcast configuration file.
Create a newhazelcast-config.xmlconfig file.src/main/liberty/config/hazelcast-config.xml
hazelcast-config.xml
link:finish/src/main/liberty/config/hazelcast-config.xml[role=include]In the server.xml file a reference to the Hazelcast config file is made using
the httpSessionCache tag. When the maven build is run
the hazelcast-config.xml
file is copied to the predefined {shared.resource.dir} directory.
There are more configuration settings you can explore in the Hazelcast Documentation.
To build the application, run the Maven install phase from the command line in the start directory:
mvn installThis command builds the application and creates a .war file in the target directory. It also
configures and installs Open Liberty into the target/liberty/wlp directory.
Next, run the Maven liberty:start-server goal for both servers:
mvn liberty:start-server -DserverName=server1
mvn liberty:start-server -DserverName=server2This goal starts an Open Liberty server instance. Your Maven pom.xml is already configured to start
the application in this server instance.
Create aCartSessionTestclass.src/test/java/it/io/openliberty/guides/cart/CartSessionTest.java
CartSessionTest.java
link:finish/src/test/java/it/io/openliberty/guides/cart/CartSessionTest.java[role=include]The testEmptyCart test makes sure that the getCart endpoint returns
empty when you first start the application. Otherwise, additional tests may cause
errors if you’re unable to access this endpoint or if data is already stored in
this session.
The testOneServer test first makes a POST request to the addToCart endpoint
and ensures that the expected response is returned. Then, it makes a GET request
to the getCart endpoint and ensures that the expected response is returned.
This test uses the same server.
The testTwoServers test makes the same checks as the previous test, but the
addToCart endpoint is on the server at port 9080, and the getCart endpoint
is on the server at port 9081.
Although REST endpoints are generally stateless, they’re used for simplicity in
this guide. The testOneServer and testTwoServers tests use a cookie
to ensure that the same person’s session data is being used for the addToCart
and getCart requests.
Verify that the tests pass using the Maven verify goal:
mvn verifyIf the tests pass, you’ll see a similar output to the following:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.cart.CartSessionTest
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.259 sec
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0You developed and tested a Java microservice using HTTP session caching and Open Liberty.