Integrating Concurrent Editing
Oxygen XML Web Author offers a feature that can be enabled to provide the ability for teams to edit and review content
concurrently. A user can share their editing session by using the Share
Session toolbar button and then sending the retrieved URL to other collaborators
and then all of them can edit and review the same document simultaneously.
Enabling the Share Session Action
To enable the Share Session action, the following conditions must
be met:
- The Concurrent Editing Plugin must be installed. It can be found in the . Make sure that you read and understand the terms and conditions of its end-user license agreement. webpage
- The
sharedSessionCompatible
loading option is set totrue
by the CMS connector plugin.
For the feature to work correctly, when a concurrent session is active, the CMS connector plugin should ensure that:
- Any save/commit action is disabled for session guests.
- Any check-in/check-out actions are disabled for session guests.
- The document is editable for guests even though they do not have a lock for it.
var mgr = editor.getEditingSupport().getConcurrentEditingManager(); if (mgr && !mgr.isCreator()) { ... }
- Concurrent editing does not work if Oxygen XML Web Author is deployed on multiple servers behind a load balancer.
-
Oxygen XML Web Author uses Web Sockets to propagate changes in real time between collaborators. If you are using a reverse proxy, some additional configuration may be required to enable Web Socket connections to the
./ws
endpoint of the application.For example, NGINX requires the following configuration for the /oxygen-xml-web-author/ws path:location /oxygen-xml-web-author/ws { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_pass "http://web-author:8080/oxygen-xml-web-author/ws"; }
As another example, when using Apache HTTP server as a reverse proxy, a system administrator needs to enable the following modules:
-
rewrite
-
proxy_http
-
proxy_wstunnel
Also, a configuration similar to the one below should be added:ProxyPass /oxygen-xml-web-author http://<internal-host>:8080/oxygen-xml-web-author ProxyPassReverse /oxygen-xml-web-author http://<internal-host>:8080/oxygen-xml-web-author RewriteEngine on RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteCond %{HTTP:Connection} upgrade [NC] RewriteRule ^/oxygen-xml-web-author/?(.*) "ws://<internal-host>:8080/oxygen-xml-web-author/$1" [P,L]
-
- Concurrent editing does not work if an existing plugin registered a
ro.sync.ecss.extensions.api.AuthorDocumentFilter
implementation.
Disabling the Share Session Action
To remove the Share Session action from the toolbar, simply
disable the Concurrent Editing Plugin in the Administration Page.
CMS-owned Concurrent Editing Sessions
Aside from using the Share Session action, a more integrated concurrent
editing approach is to have a concurrent editing room owned by the CMS.
- Ensuring that aside from the Web Author users, no other users are modifying the file. The CMS can use a "service" account to hold the "lock" on the edited file, or to do a check-out.
- Creating the concurrent editing room.
- Enabling users to join the room.
- Saving the content of the room.
- Closing the room.
Creating a Concurrent Editing Room
editor.getEditingSupport().getConcurrentEditingManager().createRoom().then(roomId =>
window.open(window.location.href + '&roomId=' + roomId))
The ID of the room can then be shared with other users. To join an existing room, the
roomId
URL parameter can be used.
By using the Java API, a room can be created like this:
String roomId = RoomsManager.INSTANCE.createRoomFromDocument(AuthorDocumentModel)
This code can be used during the editor loading on the following callbacks:
ro.sync.ecss.extensions.api.webapp.access.WebappEditingSessionLifecycleListener.editingSessionAboutToBeStarted()
. In this case, the room ID has to be added to thesessionAttributes
map using thero.sync.ecss.extensions.api.webapp.ce.Room.ROOM_ID_ATTRIBUTE
key.ro.sync.ecss.extensions.api.webapp.access.WebappEditingSessionLifecycleListener.editingSessionStarted()
. In this case, the room ID has to be added as an attribute to the editing context of the current document usingro.sync.ecss.extensions.api.webapp.ce.Room.ROOM_ID_ATTRIBUTE
as the name. The editing context can be obtained by calling:authorDocumentModel.getAuthorAccess().getEditorAccess().getEditingContext()
.
Saving the Content of the Room
To Save a document edited in a concurrent editing room, the CMS can use the room Observer, which provides the "source-of-truth" for the document content. The Observer integrates changes made by each user in batches. This helps to keep an informative version history.
For example, to implement auto-save, a CMS should:
- Add an
EditListener
on the observer (room.getObserver()
) to be notified when the document state is changed. - Periodically call
room.getObserver().sync(peerId -> { }};
. The callback is called after integrating a batch of changes from a single user. - After integrating each batch of changes, the CMS can call
room.getObserver().createInputStream()
to obtain a reader over the document content at that point. The reader should be consumed immediately.
Enabling Users to Join a Room
To enable users to join a room, there are several options:
- Add
roomId=<the-id>
as a URL parameter. - Add
roomId=<the-id>
as a loading option in a JavaScript plugin. - Set
roomId=<the-id>
as a session attribute in one of the following Java listeners:ro.sync.ecss.extensions.api.webapp.access.WebappEditingSessionLifecycleListener.editingSessionAboutToBeStarted()
ro.sync.ecss.extensions.api.webapp.access.WebappEditingSessionLifecycleListener.editingSessionStarted()
Closing the Room
A room created this way is not closed when the last user leaves. It should be closed
using Room.close()
when all the users have left and all the changes are
saved.