Skip to main content
Skip table of contents

Working with the Shadow Space

This will be a feature of the Enterprise Theme 5.1

The ShadowSpaceService provides basic functionality for other parts of the theme to store and retrieve information in the form of pages in the Bitvoodoo Enterprise Theme support space (also known as "the shadow space"). The canonical example for a shadow space client is the section configuration feature which stores customized section content in the shadow space.




shadow space

Also known as the "Bitvoodo Enterprise Theme support space", this is the archived space created and maintained by the ShadowSpaceService to store its content.

shadow page

A page stored in the shadow space and managed by the ShadowSpaceService.

shadow path

A virtual path used to identify shadow pages. E.g. the customized content for the global gu-sidebar-page section has the shadow path ["sections", ":global:", "gu-sidebar-page"] which, just like a file system path indicates a hierarchical relationship among the path segments from left to right.

shadow page editor

A customized implementation of the Confluence page editor that is used to edit shadow pages.

Shadow Paths and organization of Shadow Pages

Since a page ID is only known after the page has been created, the shadow space service uses shadow paths instead to identify pages. The shadow path represents a virtual hierarchical path in the shadow space in order to avoid conflicts. While it would technically be possible to store the shadow pages in the same hierarchical fashion (child pages) than the shadow path concept implies, this would have made the implementation of the shadow page management quite a bit more complex and was deemed unnecessary.

Instead, the shadow pages are all stored "flat" in the shadow space and a stringyfied version of the shadow path is used as the page title. For example, the shadow path with the segments ["sections", ":global:", "gu-sidebar-page"] results in a shadow page with the title "sections_:global:_gu-sidebar-page". The point here is that the implementation detail of how exactly the shadow pages are stored is irrelevant; all that matters is the ShadowPath which is used as the ID / handle for a shadow page.

Permission Checks

While everybody can view content in the shadow space defined by the permission settings of the space itself, creating and editing shadow pages is a completely different matter. With the custom shadow page editor it is possible for clients of the shadow space service to provide custom permission checkers based on the first segment of the shadow path. For example, the section service registers a custom permission checker for all shadow paths that start with the segment "sections".

Registering a new permission checker is as easy as

ShadowSpacePermissionCheckFactory.register("sections", new SectionPermissionCheck(permissionManager, spaceManager));

and the implementation of the permission checker itself can be as simple or complex as necessary. The section permission checker is quite simple; it doesn't distinguish between create and edit, and it just checks if the user is space admin or global Confluence admin:

public class SectionPermissionCheck implements ShadowSpacePermissionCheck {
	private final PermissionManager permissionManager;
	private final SpaceManager spaceManager;
	public SectionPermissionCheck(PermissionManager permissionManager, SpaceManager spaceManager) {
		this.permissionManager = permissionManager;
		this.spaceManager = spaceManager;
	public boolean hasCreatePermission(User user, ShadowPath path) {
		SectionHandle handle = new SectionHandle(path);
		if (handle.isGlobal()) {
			return permissionManager.isConfluenceAdministrator(user);
		} else {
			Space space = spaceManager.getSpace(handle.getSpaceKey());
			return space != null && permissionManager.hasPermission(user, Permission.ADMINISTER, space);
	public boolean hasEditPermission(User user, ShadowPath path, Page page) {
		return hasCreatePermission(user, path);

Every feature of the Enterprise Theme that stores content in the shadow space should define its own initial shadow path segment and permission checker.

Content Processors

Another feature of the shadow page editor is its capability to preprocess content before it is stored in the shadow space. This preprocessing is done on the level of Confluence XHTML markup and a processor can theoretically do almost anything to transform the content before it is stored. Again using the one example that currently exists, the AbsoluteAttachmentProcessor goes through the content and making attachment references absolute (explicitly pointing to the current page and the shadow space key) because otherwise the relative attachments would not work when the shadow page content is rendered in a different context (e.g. customized section content that may be rendered in the context of any other page and space).

Creating a new processor is as simple as

  1. Create a new class implementing the ShadowSpaceContentProcessor interface.

  2. Add the processor to the list of processors in the constructor of the EditShadowPageAction class.

  3. Implement the processor interface to perform the necessary transformation

Currently, there is only one list of processors for all shadow pages. In the future it might be necessary to refactor this to allow different sets of processors based on the shadow path, similar to the permission checkers.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.