Magnolia is an open-source digital business platform with a content management system (CMS) at its core. It is developed by Magnolia International Ltd. It contains standardized Java architecture that is flexible enough to customize pages and contents. Magnolia Community Edition is available under an open source GPLv3 license. The Community Edition includes an intuitive user interface, a complete Java programming API, a modern REST API, and useful templating functions for Freemarker and other languages. Magnolia stores content in the open-source Apache Jackrabbit content repository.
Multisite feature allows you to manage multiple websites in a single Magnolia instance. Besides Magnolia Enterprise Edition, Magnolia Community Edition does not support the feature provided by the multisite module. So we had to roll out our own multisite feature by extending 2 classes, URI2RepositoryMapping and URI2RepositoryManager.
The key configuration properties for URI to repository mappings are:
Magnolia’s URI2RepositoryMapping mechanism is used to map a requested URL to one of the workspaces. The most common use case is mapping a URI to the website repository, but other repositories can be addressed as well. The mechanism allows fine-tuning the mapping of the requests through prefixes (handles). If a prefix such as dam is detected in the request the requested asset is served from the repository given in the repository property. A handle can be used to build the URI.
URI to repository mapping in Magnolia is handled by two different managers depending on the edition you use.
The Community Edition allows only one site, hence its manager searches for and applies the mapping configurations defined directly at the server level.
For Community Edition, the custom mapping for each site is set at /server/URI2RepositoryMapping/mappings. The value of the ‘class’ property of a mapping node to be customized will now be a class created by extending URI2RepositoryMapping (CustomURI2RepositoryMapping). Similarly, the value of the ‘class’ property of URI2RepositoryMapping node will now be a class created by extending URI2RepositoryManager (CustomURI2RepositoryManager). An example is shown in the image below.
The CustomURI2RepositoryMapping has an additional String field named ‘host’ where the host name for that mapping can be configured. It can also be a String array if more than one host names need to be used for the particular mapping.
The URI2RepositoryManager class tries to get the mappings only comparing the URIPrefix property. This is not suitable for a multisite use case where the URIPrefix will be the root (/) for all sites. Hence, mappings with same URIPrefix (/) will be seen as duplicates and will not be accepted. So, the default URI2RepositoryManager does not help in getting all the suitable mappings.
Hence, the custom class (CustomURI2RepositoryManager) extending URI2RepositoryManager class is created. In the CustomURI2RepositoryManager class, a new comparator is used which compares the mappings using the URIPrefix as well as the host, which will be different for different sites. Hence, all the mappings under node ‘mappings’, as seen in image, get accepted.
After that, the getMapping() method returns the mapping that matches with the requested URI. This uses the logic in matches() method defined in the CustomURI2RepositoryMapping class.
The CustomURI2RepositoryMapping is created by extending URI2RepositoryMapping class, overriding matches() and getHandle() methods. In the default URI2RepositoryMapping class, the matches() method only checks whether the specified URI starts with the URIPrefix of that mapping. That is not enough for a multisite use case. So, the overriding matches() method does that and also checks that the hostname in the requested URI matches the value of the ‘host’ property for that mapping. This allows us to get the correct mapping for the requested URI.
With the correct site now identified, the system is now able to host multiple sites on the same instance and serve the correct page/resource.