Linking

Civilian provides techniques to build correct URL strings and to prevent broken links.

Introduction

Web applications sometimes need to create URLs to reference application resources: Hyperlinks in HTML responses, redirects, HATEOS locations etc. To represent URLs as strings – as it is usually done – and manually build URLs is tedious and error prone. Just think of formatting of parameter values.

Hyperlinks on the web can break, but at least they work good enough to be useful.
Being realistic about the web does not mean that we tolerate broken links within our applications. But using URL strings again makes broken links more likely: A change to the URL structure of an application requires to manually look for affected places in the code.

Civilians Path and Url classes help to avoid these pitfalls:

The Path class

The Path class provides a normed representation of path strings:
  • The root path is represented as empty string ""
  • Any other path always starts with a '/' but never ends with a '/' character.
The Path class supports common operations like adding two paths.
Many core objects like Server, Application, Request, Resource etc. are associated with an absolute path from the server root and a relative path with regard to some parent context. They implement the interface PathProvider to give access to these paths.

The Url class

The Url class is a builder class to construct URL strings and guarantees a syntactical correct form of the URL.

To create a Url object you need to call a Url constructor, passing the request object (or a RequestProvider like a Controller) and an additional argument which describe the URL path:

  • or a simple URL or path string, in case you want to address resources outside of the application (or address interal resources in an unchecked way).
  • a Path to build an Url for that path
  • a PathProvider like the Application or the Request to build an Url for the path of that provider.
  • a Controller class to build a URL to the resource which is processed by that Controller.
  • a Resource to build a URL to that resource.
RequestProvider rp = ...
Url url;
url = new Url(rp, "https://example.org/some/path");
url = new Url(rp, getApplication());
url = new Url(rp, SearchController.class);
Once constructed a Url object can be tweaked in many ways:
  • Add or change query parameters in a type-safe way
  • Add additional path segments or a fragment identifier
Url url = ...
url.addQueryParam("page", 5);
url.setFragment("details");
To retrieve the URL string simply call Url.toString(). Behind the scenes this method does some automatic magic:
  • Percent encoding of parameters is automatically applied.
  • It inserts a session id into the URL if the client does not accept session cookies. (You can also turn of this automation).
If the Url is constructed from a Controller class or Resource object (see next chapter), it is easy to detect broken links. For example, delete a Controller class, and the compiler will tell you where is was used to build an Url.
When constructed in such a way, the Url also knows about path parameters in the URL string and allows you to fill in values for them.
Url url = new Url(rp, MasterDataController.class);
url.setPathParam(CrmPathParams.CUSTOMERID, 123);

Use resource constants to create Urls

At runtime Civilian knows all the dynamic resources exposed by an application, the path parameters which are part of the path schemes of the resources, and which controller processes requests for a resource.
This knowledge allows Civilian to associate a resource with a request and dispatch the request to its controller.

Normally this resource tree is built at application startup, by scanning the classpath for the applications controller classes.

But Civilian also allows you to generate a special Java class from the resource tree, which defines a Java constant of type Resource for every dynamic resource in the application. An Url to a resource can now also be built by using that constant, as alternative to passing the corresponding controller class.

Again, change your resource tree, then regenerate the constants interface, and the compiler will tell you all places in your code which need adjustments. Broken links, no more.

Example use of Resource constants

In the CRM sample we generated interface org.civilian.samples.crm.web.CrmResources which defines constants for all resources of the CRM application. To build a Url to resource /customers/{customerId}/masterdata, we write

Url url = new Url(CrmResources.root.customers.$customerId.masterdata);
...
String s = url.toString(); // at the end convert to a string to be used in the template

The Resource constants generator

org.civilian.tool.resource.ServerConstGenerator is the tool to generate the constants interface. It prints a detailed help message when run without any arguments. ServerConstGenerator expects the name of your application class and optional parameters:
java org.civilian.tool.resource.ServerConstGenerator param* app-class
One of the -out:* parameters must be used to the determine the location of the generated file:
-out:package <directory> writes the output file into the package directory below the given package root directory
... -out:package src/main/generated ...
-out:dir <directory> writes the output file into the given directory.
-out:file <file> writes the output file to the given file.
The -name parameter sets the name of the generated interface. By default a name is derived from the name of the application class. If the name is a simple name, it is qualified package of the application class.
... -name MyResources ...
The -enc parameter sets the encoding of the generated file. By default the encoding is UTF-8.
... -enc ISO-8859-1 ...
The -v parameter turns on verbose messages, the -ts parameter causes a timestamp to be written into the generated file.

Avoid the classpath scan at application start

When Civilian starts an application, it scans the classpath to find the applications Controller classes and then constructs the resource tree. The resource constants interface does contain the exact same information and can be used to avoid the scan. Just register during app initialization:
public class MyApp extends Application {
    ...
    protected void init(AppConfig config) {
        ...
        config.setResourceRoot(MyResources.root);
    }
}
But remember to regenerate the resource constants interface when you change the resource tree. Another idea might be to only explicitly set the resource root in production mode.

Client-side linking

The techniques described so far are available on the server. But suppose we write a client program to access server resources. Again we don't want to build URLs out of error prone strings.
Since the Resource and Url classes are bound to a server-side execution context we cannot use them directly. Instead Civilian provides the WebResource and WebUrl classes for use in a client program.

To obtain a Java interface defining WebResource constants exposed by the application, we use the command-line tool ClientConstGenerator.

java org.civilian.tool.resource.ClientConstGenerator param* app-class
Its command-line parameters are similar to that of the server generator. Run the generator without parameters to obtain a detailed help message.

The client sample demonstrates how to use WebUrl and WebResource.

Right now only a constants interface for a Java client can be generated. We plan to add a similar output for JavaScript in a future release.