Last updated Dec 8, 2017

Renamable users in Confluence 5.2

With Confluence 5.2, we are introducing schema and API changes necessary to support the ability to change usernames. To make that possible, users will have a new, unique, permanent key as well as the already-existing, unique, changeable username.

As usernames will be able to change, your plugin will need to migrate its existing data to user keys instead of usernames.

The complete rename user functionality will be delivered in 5.3. However the schema and API changes necessary will be released in 5.2 and recommend developers begin updating their add-ons now.

Introducing the user key

Previously the username field was used as a display value and also stored as the primary key of the user. In order to allow usernames to be changed, we need a separate identifier that is unchangeable.

We have introduced a new field on the user, called "key". It is a case-sensitive UUID string and will never change for a given user.

When to use the key, when to use the username

The key should be considered the primary key of the user.

Whenever you want to store a reference to a user in long-term storage (for example, the Confluence database DB or the Lucene index) you should use the key, because it can never change.

However, the key should never be shown to the end user. Only the username should be displayed.

The username is a unique secondary key, but should not be stored in long-term storage because it can change over time.

The new ConfluenceUser object

We have introduced a new Interface to represent users, called com.atlassian.confluence.user.ConfluenceUser. It extends the existing com.atlassian.user.User interface with a new method called getKey() that returns the key for the user.
To get hold of a ConfluenceUser object you can call either UserAccessor#getUserByKey(key) or UserAccessor#getUser(username).

Converting the User object to the ConfluenceUser object

To support backwards compatibility, all of the existing API still allows the use of the legacy User interface. We're allowing for the possibility that you want to migrate your existing code over time, as and when required.

We have provided a helper Class (com.atlassian.confluence.user.persistence.dao.compatibility.FindUserHelper) that allows you to quickly convert User objects to ConfluenceUser objects using the getUser(User) method.

See the FindUserHelper Javadoc for more information.

Important changes to be aware of

When storing information in the database, you must now use the key of the user, not the username.

Confluence API methods that previously accepted or returned a username or User object are in some cases now deprecated and replaced with alternatives based on ConfluenceUser.

You should check the API of such methods and consider using alternative methods that take or return the ConfluenceUser object.

Where applicable, you should write SAL and Active Objects upgrade tasks to migrate existing data containing usernames to contain user keys:

Cross-version compatibility

If you want to create plugins that are compatible with both Confluence 4.3 and Confluence 5.2 onwards, you have a few options:

  • Option 1: Continue using usernames
  • Option 2: Use the Confluence compatibility library and execute upgrade tasks conditionally
  • Option 3: Use the SAL compatibility library

Option 1. Continue using usernames

If your plugin does not persist usernames at all, or if user-related data can safely be lost for renamed users, your plugin can continue using the Confluence 4.3 API.

Option 2. Use the compatibility library and execute upgrade tasks conditionally

We provide a compatibility library that your plugin can include, so that it can interact with Confluence 4.3 or 5.2 in a safe manner.

To add the compatibility library as a Maven dependency, add the following to your pom.xml:

1
2
 <dependency>
   <groupId>com.atlassian.usercompatibility</groupId>
   <artifactId>usercompatibility-confluence</artifactId>
   <version>2.1.4</version>
</dependency>

See the comments on the helper class UserCompatibilityHelper for details.

When using the compatibility library, the plugin should also ensure that SAL and Active Objects upgrade tasks that perform user migration are executed only when UserCompatibilityHelper.isRenameUserImplemented() returns true. This is because UserCompatibilityHelper will process usernames in Confluence versions earlier than 5.2, and userKeys thereafter.

You can make SAL plugin upgrade tasks conditional, by making the getBuildNumber() method return 0 if UserCompatibilityHelper.isRenameUserImplemented() returns true

Making PluginUpgradeTask Conditional

1
2
public int getBuildNumber()
{
    return UserCompatibilityHelper.isRenameUserImplemented() ? 8 : 0;
}

You can make the Active Objects upgrade task conditional, by making getModelVersion() return 0 if UserCompatibilityHelper.isRenameUserImplemented() returns true.

Making ActiveObjectsUpgradeTask Conditional

1
2
public ModelVersion getModelVersion()
{
    return ModelVersion.valueOf(UserCompatibilityHelper.isRenameUserImplemented() ? "8" : "0");
}

If you later add other upgrade tasks, you must update the conditional user key migration upgrade tasks to have the highest build number or model version, and to make them idempotent (runnable multiple times without changing the end result), because changing the build number or model version might cause the upgrade tasks to run again.

Option 3. Use the SAL compatibility library

If you are working on a cross-product plugin you will probably prefer to use the SAL User Compatibility Library. You can also use this library for a Confluence-only plugin, instead of following option 1 above.

Cross-product plugin development using Shared Access Layer (SAL)

If you develop a cross-product plugin, you are probably using the Shared Access Layer to interact with the different products in a generic way.

Note: From version 2.10, SAL will be updated to better handle the fact that a user's username can change.

UserManager and UserProfile

For access to a user's key, the UserProfile interface now includes a getUserKey() method. As explained above, if you need to store a reference to a user, you should do so by storing the user key, not the username.

Most of the methods in UserManager that used to take a username as a parameter are now deprecated in favour of methods that take a UserKey object. Similarly, the getRemoteUsername() methods in UserManager, which return a username as a String, are now deprecated in favour of methods that return a UserProfile or a UserKey object.

Other services

All the methods in UserSettingsService and SearchProvider have been similarly modified: methods that take a username as a parameter are now deprecated, and new methods taking a UserKey have been added.

Rate this page: