...
There is a client that wants to support large numbers of tenants (800+) and have each tenant be able to perform some minimal customization for their particular skin. At least initially, the customizations are to select a few colors that are unique to their tenant institution to apply to the skin. Eventually there may be other elements that that the tenant administrators can control. The tenant administrators will be non-developer personnel (secretaries / general school staff) so they need a very simple UI interface for making and applying the changes.
There is a separate but related effort for supporting large numbers of tenants where a 'tenant template' is a set of fragment definitions, fragment layouts, portlet definitions, and other data that are applied (dynamically adjusted and imported) when a uPortal system administrator creates a new tenant. This tenant creation / deletion process must be a very simple process to create a tenant and have a tenant immediately operational, but also allows the tenant to do basic, minimal customizations to their tenant configuration (again by staff that are non-technical) using the uPortal's Administrative UIs.
Design
One idea for addressing this need is to have a 'Skin manager' that is one of the portlet definitions in the tenant template and allows the tenant administrator to configure their tenant's skin / color scheme. As a design simplification, the skin manager uses CONFIG mode to allow the tenant administrator to configure portlet preference values that are applied to the 'template skin'. The tenant's fragment layouts (from the tenant template) include the Skin Manager portlet instance in the page-top or preHeader region to apply the template to authenticated users (and possibly guest users though this requires a scheme such as a servlet filter to identify the appropriate tenant based on URL parameters or similar if a site has multiple tenants). The skin manager rendering in non CONFIG mode is responsible for rendering whatever content is necessary to render the tenant's skin appropriately.
When the portal page is rendered for a user, the rendering side of the Skin Manager checks to see if the compiled skin is available (based on the skin's portlet preference values) and if so provides the markup needed to include the skin in the page. If the skin is not available, the skin's portlet preference values are used to compile a skin that is then available for the user in a just-in-time fashion. The compiled skin is currently stored on the file system in the same location as the regular skin files (e.g. /media/skins/*.css) with a file name that is unique to its skin configuration (currently a hash of the portlet preference values). This 'just in time' approach accomplishes several things:
- On a fresh deploy where the configured skin is not available, or after an administrator makes skin configuration changes, the skin is created and stored on the file system when it is needed.
...
- Allows the skin to be created and available on each system in a cluster.
- Skin compilation is fairly expensive. Potentially spreads skin compilation time out over a period of time
Some negatives of this approach are that
- One or more users on each node in a cluster are hit with the skin compilation time, instead of just the administrator.
- Deployments of new uPortal code will wipe out all existing skins since they are part of the webapp folder structure and they will need to be compiled again. Saving the compiled skin into the database would allow for only the admin to be hit with the expensive process and other nodes in a cluster could simply retrieve the compiled result.
Design goals
- Simplified design that fit within client's budgetary constraints, but can be used as a base for more dynamic and feature rich enhancements in the future
- Extremely simple Skin Management UI that non-technical users assigned to perform tenant administrative tasks can use to adjust their skin look
- Skin configuration changes must apply immediately and not require a server restart
- Skin configuration changes apply immediately to all servers in a cluster without administrative intervention
- Approach that can be used in non-tenant situations to allow for simple, basic adjustments to a general uPortal skin experience, hopefully growing more sophisticated over time
- Leverage if possible the same skin technologies used for Respondr
- Do not require duplication of Respondr skin files to allow for configurable skinning to ease long term maintenance.
- Be able to handle a large number of tenants, upwards of 800+, with reasonable system resource impacts.
The Skin Manager is NOT intended to significantly alter the skins as would be done for a typical University deployment where the University's staff would typically generally copy Respondr's default skin and modify the source files to achieve the desired skin appearance.
Future
- Expand the number of skin variables and possibly include images or other elements to allow the skin to be more heavily configured.
- Allow the administrator to 'preview' the skin changes in a way that only the administrator sees the affects of the changes until the skin changes are persisted.
- Enhance the security infrastructure to limit the users who can configure a skin so a delegated administrator can affect only their skin and not other tenant's skins.
- Expand to a database-driven strategy where the skin is stored in the database and not necessarily on the file system.
Opportunities for consideration
- Move skin compilation into an asynchronous task on a non-render thread, getting the details right so that uPortal rendering does not block on in-process skin (re-)compilation and users do not get half-baked in-process skin artifacts during skin (re-)compilation.