Using domains

This section explains how you can use the domain concept directly in your controllers or business logic.

Accessing the current domain

You can access the current domain or its metadata using one of the methods on the WebCmsMultiDomainService. From a static context, you can directly use the WebCmsDomainContextHolder and WebCmsDomainContext.

Use the service wherever possible, as it will ensure correct behaviour in both a multi-domain and no-domain context.

Mapping handler methods to domain

Most web cms mapping annotations allow you to specify the domain for which they apply. If you want to create regular @RequestMapping handler methods for specific domains, you can add the @WebCmsDomainMapping annotation.

Example declaring a domain-specific handler method
/**
 * Declare a handler method that should only execute on the WebCmsDomain with domain key 'my-domain'.
 */
@GetMapping("/my-handler")
@WebCmsDomainMapping("my-domain")
public String domainSpecificMethod() {
  ...
}

Entity Query Language extensions

WebCmsModule adds some domain-related functions that can be used in EQL statements:

  • selectedDomain() returns the current domain of the context

  • visibleDomains() returns the domain from which entities can be selected, usually this is the current domain together with non-domain bound entities

  • accessibleDomains(ACTION, ACTION, …​) returns the list of domains for which the user has any of the listed actions

  • action should be String representing a valid AllowableAction

The multi-domain auto-configuration will adjust views and selections only be specifying default EQL predicates to apply, containing these functions.

Resolving the current domain

The current domain is resolved in 2 ways:

  1. The AbstractWebCmsDomainContextFilter is used on every request to determine the initial domain. The default implementation is the WebCmsSiteConfigurationFilter that will use the hostname of the request to lookup the matching WebCmsSiteConfiguration metadata and select the domain accordingly.

  2. The CookieWebCmsDomainContextResolver is used by AdminWebModule to determine the actual domain configured in a cookie. This will overrule any previously configured domain by the filter.

You can alter the resolving mechanism by creating your own AbstractWebCmsDomainContextFilter implementation and registering it on the WebCmsMultiDomainConfiguration.

When the domain is changed via the GUI, the CookieWebCmsDomainContextResolver will send out an event. The WebCmsDomainChangedEvent will contain the currentDomain (the domain being switched from), and the newDomain (the domain being switched to).

You could for example use this event to reload the Authorities of the current user, when the authorities differ per domain.

Example reloading authorities for a user
    @EventListener(WebCmsDomainChangedEvent.class)
    public void reloadAuthorities( WebCmsDomainChangedEvent event ) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        WebCmsDomain domain = webCmsMultiDomainService.getDomain( event.getNewDomain() ); (1)

        Collection<? extends GrantedAuthority> authorities = buildAuthoritiesForDomain( auth.getPrincipal(), domain ); (2)
        Authentication newAuthentication;
        if ( auth instanceof UsernamePasswordAuthenticationToken ) {
            UsernamePasswordAuthenticationToken usernamePasswordAuthentication = (UsernamePasswordAuthenticationToken) auth;
            newAuthentication = new UsernamePasswordAuthenticationToken( usernamePasswordAuthentication.getPrincipal(), usernamePasswordAuthentication.getCredentials(),
                                                               authorities );
           SecurityContextHolder.getContext().setAuthentication( newAuthentication ); (3)
        }
    }
1 Get the new domain from the event.
2 Create your own function to build all the authorities applicable to this domain.
3 Set the newly built Authentication object containing the new authorities.

Using no-domain in a multi-domain setup

In a multi-domain setup items not attached to a specific domain are expected to be shared across all domains. In the default configuration, type specifiers are not domain-bound but shared across all domains. In the administration UI of per-domain management, you will only be able to modify types under Shared settings.

It’s possible to define an item as domain-bound however, but at the same time making the domain optional. This means the entity can be either shared across all domains, or attached to a specific domain.

The following default behaviour will be applied:

  • if an entity is not domain-bound, it will always be looked for in the set of "no-domain" entities, regardless of any domain attached to the current context

  • if an entity is domain-bound, it will be looked for in the entities attached to the domain of the current context (this could be "no-domain")

  • if an entity is domain-bound but the domain is optional, it will be looked for in the set of "no-domain" entities if no entity could be found in the set of entities attached to the domain of the current context

  • This allows you to use entities shared across all domains, but overrule them with domain-specific versions. This can be especially useful in the case of type specifiers.

The available service beans all inspect the multi domain configuration of your application to determine which logic they should apply. This will usually be very transparent for the user \(developer\).