A client recently asked if it was possible to have an Alfresco Share theme applied to one particular site and not to the rest of the sites or user dashboards? What they wanted was basically to be able to configure a different theme per site. So for example, a training related site would use one theme (e.g. blue inspired) and a knowledge base site would use another theme (e.g. green inspired).

Users would then learn after a while that the training site is styled with a blue theme and whenever they see a blue styled page it has a training subject matter. Other documentation and posters could then also match that blue theme.

Out of the box functionality that we can use for this

So is there anything out-of-the-box with Alfresco Share that supports configuring themes per site? Not really (see http://issues.alfresco.com/jira/browse/ALF-1949), the only thing that I found that is useful is the possibility to append a theme parameter to all URLs and then the page would be displayed with that theme.

For example, the following document library page in a site with id test will be displayed with the Google Docs theme (no matter what theme has been setup for Alfresco Share) when calling it with the following URL:

http://localhost:8080/share/page/site/test/documentlibrary?theme=gdocs

So if we could just intercept the incoming requests to /page/site/* we could append the theme parameter and define the themes that we want to use for the different sites in the normal way.

This can be done with a Servlet Filter.

Implementing a Servlet Filter to append the theme parameter

A Servlet Filter can be used to append a HTTP Request parameter by wrapping the request before it is sent for processing. We would first configure the filter with the site IDs and the themes that should be used for these site IDs:

<filter>
...
	<init-param>
		<param-name>sites</param-name>
		<param-value>helloworld,test</param-value>
	</init-param>
	<init-param>
		<param-name>themes</param-name>
		<param-value>default,gdocs</param-value>
	</init-param>
</filter>

The sites filter parameter contains the identifiers for the sites that we want to set themes for and the themes filter parameter contains the theme identifiers. In this case the site with the id helloworld will use the default theme and the test site will use the Google Docs theme (gdocs).

We can then use these parameters in the implementation of the filter:

package com.ixxus.cms.util;

import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public final class ThemeAppenderFilter implements Filter {
	private static final String SITE_NAMES_FILTER_PARAMETER_NAME = "sites";
	private static final String SITE_THEMES_FILTER_PARAMETER_NAME = "themes";
	private static final String THEME_URL_PARAMETER_NAME = "theme";
	static Map m_site2themeMap;

	static class ModifiedRequest extends HttpServletRequestWrapper {
		public ModifiedRequest(ServletRequest request) {
			super((HttpServletRequest)request);
		}

		@Override
		public String getParameter(String paramName) {
			String value = super.getParameter(paramName);
			if (THEME_URL_PARAMETER_NAME.equals(paramName)) {
				value = m_site2themeMap.get(getSiteId(getRequestURI()));
			}
			return value;
		}

		private String getSiteId(String url) {
			String siteId = null;
			String temp = url.substring(url.indexOf("/site/") + 6);
			siteId = temp.substring(0, temp.indexOf("/"));
			return siteId;
		}
	}

	public void init(FilterConfig filterConfig)
	throws ServletException {
		m_site2themeMap = new HashMap();
		String sites = filterConfig.getInitParameter(SITE_NAMES_FILTER_PARAMETER_NAME);
		String themes = filterConfig.getInitParameter(SITE_THEMES_FILTER_PARAMETER_NAME);
		StringTokenizer st = new StringTokenizer(sites, ",");
		StringTokenizer st2 = new StringTokenizer(themes, ",");
		while (st.hasMoreTokens()) {
			if (st2.hasMoreTokens()) {
				m_site2themeMap.put(st.nextToken(), st2.nextToken());
			}
			else {
				System.out.println("The '" + SITE_THEMES_FILTER_PARAMETER_NAME +
				"' filter parameter has not been specified correctly, it is missing theme specs for one or more sites");
			}
		}
	}

	public void destroy() {}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
	throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		chain.doFilter(new ModifiedRequest(httpRequest), response);
	}
}

In the ThemeAppenderFilter class we define a nested class ModifiedRequest that wraps the incoming HTTP request, this inner class overrides the getParameter method that some Alfresco Share framework Servlet will call to see if the theme parameter is available. When this happens we intercept it and give it back the theme that has been configured for the site. When the filter is initialized we setup a Map with siteId -> themeId mappings.

This class can be built against the standard Alfresco SDK and then put in a JAR file that is copied into the alfresco/tomcat/webapps/share/WEB-INF/lib folder.

Sites that are not configured with a specific theme will use the currently configured theme for Alfresco Share.

Deploying the Theme Appender Servlet Filter

The filter should be deployed by configuring the following entries in the web.xml file that is located in the alfresco/tomcat/webapps/share/WEB-INF folder:

<!--
Alfresco Share related filter.
Theme Appender Filter that will append a theme parameter (e.g, ?theme=default)
to incoming site URLs. Appended theme is determined by configuration in this filter
-->
<filter>
	<filter-name>ThemeAppenderFilter</filter-name>
	<filter-class>com.ixxus.cms.util.ThemeAppenderFilter</filter-class>
	<init-param>
		<param-name>sites</param-name>
		<param-value>helloworld,test</param-value>
	</init-param>
	<init-param>
		<param-name>themes</param-name>
		<param-value>default,gdocs</param-value>
		</init-param>
</filter>

<!-- Theme Appender Filter should match URLs like
	http://localhost:8080/share/page/site/test/helloworldhome -->
<filter-mapping>
	<filter-name>ThemeAppenderFilter</filter-name>
	<url-pattern>/page/site/*</url-pattern>
</filter-mapping>