3.5.13.2. Routing API

This section describes the key concepts of the routing API.

Route Registration

In order to register a route for a screen, add the @Route annotation to the screen controller, for example:

@Route("my-screen")
public class MyScreen extends Screen {
}

The annotation has three parameters:

  • path (or value) is the route itself;

  • parentPrefix is used for routes squashing (see below).

  • root is the boolean property which enables to specify whether a route is registered for the root screen (like Login screen or Main screen). The default value is false.

    If you create a root screen with the path other than the default login and make it available by a link without login, you should enable it for the anonymous user. Otherwise, when users enter the URL like /app/#your_root_screen they will be re-directed to the /app/#login link instead of opening your root screen.

    1. Set cuba.web.allowAnonymousAccess = true in the web-app.properties file.

    2. Enable the created screen for anonymous users: start the application, go to Administration > Roles, and create a new role with access to your screen. Then assign the created role to the anonymous user.

If you need to define a route for a legacy screen add the route (and optionally routeParentPrefix equivalent to the parentPrefix parameter, rootRoute equivalent to the root parameter) attribute to the screen’s element in the screens.xml file, for example:

<screen id="myScreen" template="..." route="my-screen" />
Route Squashing

This feature is designed to keep the URL clean and readable when opening multiple screens with routes having the same parts.

Suppose that we have browser and editor screens for the Order entity:

@Route("orders")
public class OrderBrowser extends StandardLookup<Order> {
}

@Route("orders/edit")
public class OrderEditor extends StandardEditor<Order> {
}

URL squashing is used to avoid repeating of the orders route in the URL when the editor screen is opened right after browser. Just specify the repeated part in the parentPrefix parameter of the @Route annotation on the editor screen:

@Route("orders")
public class OrderBrowser extends StandardLookup<Order> {
}

@Route(value = "orders/edit", parentPrefix = "orders")
public class OrderEditor extends StandardEditor<Order> {
}

Now when the editor is opened in the same tab as the browser, the resulting address will be like app/#main/0/orders/edit?id=…​

Mapping of UI State to URL

The UrlRouting bean allows you to change the current application URL according to the current screen and some parameters. It has the following methods:

  • pushState() – changes the address and pushes new browser history entry;

  • replaceState() – replaces the address without adding new browser history entry;

  • getState() – returns a current state as NavigationState object.

The pushState()/replaceState() methods accept the current screen controller and optional map of parameters.

See an example of using UrlRouting in the section below.

Navigation Filter

The navigation filters mechanism allows you to prevent transition to some routes.

A navigation filter is a Spring bean that implements the NavigationFilter interface. The @Order annotation can be used to configure the order of invocation of all navigation filters. The NavigationFilter.HIGHEST_PLATFORM_PRECEDENCE and NavigationFilter.LOWEST_PLATFORM_PRECEDENCE constants define the range which is used by filters defined in the framework.

The NavigationFilter interface has the allowed() method which accepts two arguments: current navigation state fromState and requested navigation state toState. The method returns AccessCheckResult instance and checks whether the transition from the current navigation state to the requested navigation state is allowed.

CubaLoginScreenFilter is an example of navigation filter. It is designed for checking whether the current session is authenticated to prevent navigation to the login screen when the user is logged in already:

@Component
@Order(NavigationFilter.LOWEST_PLATFORM_PRECEDENCE)
public class CubaLoginScreenFilter implements NavigationFilter {
    @Inject
    protected Messages messages;

    @Override
    public AccessCheckResult allowed(NavigationState fromState, NavigationState toState) {
        if (!"login".equals(toState.getRoot())) {
            return AccessCheckResult.allowed();
        }
        boolean authenticated = App.getInstance().getConnection().isAuthenticated();
        return authenticated
                ? AccessCheckResult.rejected(messages.getMainMessage("navigation.unableToGoToLogin"))
                : AccessCheckResult.allowed();
    }
}