Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

An Alternative Navigator in Vaadin

DZone's Guide to

An Alternative Navigator in Vaadin

When it comes to managing views for Vaadin apps, consider storing the state in a place inaccessible to users using a built-in implementation.

· Java Zone ·
Free Resource

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

In Vaadin, to change the components displayed on the screen, there are a few options. The most straightforward way is to use the setContent() method on the UI. The most widespread way is to use the navigator.

Views managed by the navigator automatically get a distinct URI, which can be used to be able to bookmark the views and their states and to go back and forward in the browser history.
— Vaadin documentation

This is the main asset for apps managing catalogs, such as e-commerce shops, or item management apps. Every item gets assigned a specific URL, through fragment identifiers.

However, the view per URL trick is also a double-edged blade. It lets the user bypass the server-side navigation and directly type the URL of the view they want to display in the browser. Also, the View interface requires implementing the enter() method. Yet, this method is generally empty and thus is just boilerplate.

Let’s see how we can overcome those issues.

A Solution to the Empty Method

With Java 8, it’s possible for an interface to define a default implementation. Vaadin takes advantage of that by providing a default empty method implementation:

public interface View extends Serializable {

    public default void enter(ViewChangeEvent event) {
    }

    ...
}


Even better, all methods of the View interface are default. That lets you implement the interface without writing any boilerplate code and relying on default behavior.

A Solution to the View per URI

The Default Implementation

The navigator API consists of the following classes:

Navigator API class diagram

As can be seen, the handling of the view by the URI occurs in the UriFragmentManager class. This implementation relies on the fragment identifier in the URL. But this is only the default implementation. The topmost abstraction is NavigationStageManager, and it has no constraints on where we can store the state.

An Alternative

To prevent users from jumping to a view by typing a specific URL, one should store the state in a place inaccessible to them. For example, it’s feasible to store the state in cookies. A simple implementation could look like:

private const val STATE_KEY = "state"

class CookieManager : NavigationStateManager {

    private var navigator: Navigator? = null

    override fun setNavigator(navigator: Navigator) {
        this.navigator = navigator
    }

    override fun getState(): String {
        val cookies = VaadinService.getCurrentRequest().cookies?.asList()
        val value = cookies?.find { it.name == STATE_KEY }?.value
        return when(value) {
            null -> ""
            else -> value
        }
    }

    override fun setState(state: String) {
        val cookie = Cookie(STATE_KEY, state)
        VaadinService.getCurrentResponse().addCookie(cookie)
    }
}


Creating a navigator using the previous state manager is very straightforward:

class NavigatorUI : ViewDisplay, UI() {

    override fun init(vaadinRequest: VaadinRequest) {
        navigator = Navigator(this, CookieManager(), this)
    }

    override fun showView(view: View) {
        content = view as Component
    }
}


At this point, it’s possible to place components that change the view on the UI and spy upon the request and response. Here are the HTTP request and response of an AJAX call made by Vaadin to change the view:

POST /UIDL/?v-uiId=0 HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Content-Length: 297
Origin: http://127.0.0.1:8080
User-Agent: ...
Content-Type: application/json; charset=UTF-8
Accept: */*
DNT: 1
Referer: http://127.0.0.1:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: state=Another; JSESSIONID=B584B759D78A0CDBA43496EF4AEB3F25

HTTP/1.1 200
Set-Cookie: state=Third
Cache-Control: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 850
Date: Fri, 27 Oct 2017 09:19:42 GMT


Conclusion

Before Vaadin 7, I personally didn’t use the Navigator API because of the requirement to implement the enter() method on the view. Java 8 provides default methods, Vaadin 8 provides the implementation. There’s now no reason not to use it.

If the default fragment identifier way of navigating doesn’t suit your own use case, and it’s also quite easy to rely on another way to store the current view.

More generally, in its latest versions, Vaadin makes it easier to plug in your implementation if the default behavior doesn’t suit you.

The complete source code for this post can be found on GitHub in Maven format.

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

Topics:
java ,vaadin ,navigator ,state ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}