Confluence 6.9 EAP released - read-only mode is coming!

We do use some com.atlassian.confluence.plugin.descriptor.web.conditions.ReadWriteAccessModeCondition conditions in atlassian-plugin.xml to hide certain menu items, but we also need to check for Read-only mode inside Java code. Any idea when the compatibility library will land? We can’t release a future-proof version of our add-on that’s aware of the Read-only mode until we can make it run on older versions of Confluence. There’s always an option to use reflection, but we’d really love to avoid it.

This is ugly, but to for now we resorted to using Reflection when working with AccessModeService to ensure backwards compatibility with previous versions of Confluence. Example wrapper method:

    public boolean isReadOnly() {
        boolean result = false;
        Object accessModeService = ContainerManager.getInstance().getContainerContext().getComponent("accessModeService");

        if (null != accessModeService) {
            try {
                result = (boolean) accessModeService.getClass().getMethod("isReadOnlyAccessModeEnabled", null).invoke(accessModeService);
            } catch (Exception e) {
                log.error("Cannot determine whether readonly mode is enabled ", e);
            }
        }

        return result;
    }

Feedback welcome. Can’t wait for the compat library to be out!

1 Like

Hey App vendors, thanks so much for your engagement and support in making your Apps compatible with read-only mode whilst we continue to develop it. With the 6.9 Beta shortly upon us, we have had to make the decision to bump the feature from this release as it is not quite production ready. The good news is that in the coming couple of weeks we expect to be completed from the Atlassian side and that will give you a little extra time to get your App compatible for when the feature is released in 6.10.
Keep an eye on the EAP updates as we have 1-2 more deliverables to make it a simpler for plug-ins to be compatible with read-only mode, whilst not breaking your backward compatibility with earlier Confluence versions.

Thanks again for you ongoing support.
Adam - Confluence PM

4 Likes

Hi,

When read only mode is activated and it is checked if a user has EDIT permission on a specific page the result is always “false” (using the PermissionManager “hasPermission()”). How can we know if that user really has EDIT permissions on that page if our app relies on that info for our own functionalities?

Could you provide a method that ignores read only mode to check EDIT permissions?

Thank you,

Pablo

1 Like

Hi,
I’ve seen different contradicting statements regarding this:
Confluence 6.9 EAP released - read-only mode is coming! - Atlassian Developer Blog - says it’s in 6.9
https://confluence.atlassian.com/doc/confluence-6-9-0-beta-release-notes-947849643.html - now says it’s NOT in 6.9, I think yesterday it still said it’s in 6.9

Due to @abarnes message and the updated release notes page I expect it NOT to be in 6.9, but maybe @rwhitbeck could update the blog post :wink:

Cheers,
Jens

1 Like

Thanks for pointing that out. I’ve updated the main post and the blog post with the quote from @abarnes so it’s front and center.

Sorry Jens, totally my fault. I forgot about some of the places that read-only mode had been mentioned (it is also incorrectly mentioned in the email you may have received about the beta).

I can confirm that Read-only mode will not be available for customers in Confluence 6.9. We hope to make it available in the next release - expect to see some new EAP milestones in the next week or so.

When read only mode is activated and it is checked if a user has EDIT permission on a specific page the result is always “false” (using the PermissionManager “hasPermission()”). How can we know if that user really has EDIT permissions on that page if our app relies on that info for our own functionalities?

Would you please copy and paste the code snippet that checks for the user’s EDIT permission?

Thanks,
Tam

The code that checks if the user has EDIT permissions is:

permissionManager.hasPermission(user, Permission.EDIT, page)

Hi @pablo1,
You can use the same annotation (i.e. ReadOnlyAccessAllowed) on an Action class/package/method as on a REST endpoint. Normally, Confluence will bypass the check and display the desired page instead of the Not Permitted page if the corresponding action is annotated (with mentioned annotation). If there are any other edge cases that the annotation cannot help, please let me know.

Regards,
Tam

Hi @ttranminh,

here’s some late feedback on the compat library:

We had to add the following snippet to all of our products because the compat library does not check on its own for availability of RO mode when using withReadOnlyAccessExemption:

    private <T> T withReadOnlyAccessExemption(Callable<T> callback) {
        // accessModeCompatService.withReadOnlyAccessExemption always tries to call the same method on AccessModeService, so it will fail
        // on Confluence < 6.10. So we only call it when read-only mode is enabled, because then we know that AccessModeService is
        // available.
        if (accessModeCompatService.isReadOnlyAccessModeEnabled()) {
            return accessModeCompatService.withReadOnlyAccessExemption(callback);
        } else {
            try {
                return callback.call();
            } catch (Exception e) {
                // Should never happen
                throw new RuntimeException(e);
            }
        }
    }

Are there any plans to update the compat library?

It would make the compat library so much easier to use if it did check that on its own because then client code could simply call withReadOnlyAccessExemption without worrying about the Confluence version / RO mode.

Cheers,
Jens

1 Like

Hi @jens,
The withReadOnlyAccessExemption method will throw a ServiceException if the method is not found. You can catch this exception instead of doing a check with isReadOnlyAccessModeEnabled (since it’s costly). I suggest you doing this:

try {
	withReadOnlyAccessExemption(callable);
} catch (ServiceException e) { // that means R/O mode is not a thing prior to 6.10
    try {
        callback.call();
    } catch (Exception e) {
        // Should never happen
        throw new RuntimeException(e);
    }
}

Cheers,
Tam

Hi @ttranminh,

thanks for the example.

If that operation really is costly (and that’s not mentioned in the javadocs) wouldn’t it then make even more sense to let the compatibility library handle that case in an efficient manner? Or at least update the javadocs.

Nevertheless I want to say thanks for providing the compatibility library. It has helped us with quite a few projects.

Cheers,
Jens