Testing collaboration on one machine¶
How to run two Protégé instances against a local server and exercise the whole feature. No Docker, no backend, no database — the bridge runs on its own and tokens can be minted by hand.
Before you start: the ontology needs an absolute IRI¶
Collaboration cannot work on a project whose ontology IRI is a relative string. Protégé resolves a
relative rdf:about against the file's own location on save, so an ontology declared as
becomes something like file:/C:/Users/you/projects/thing/src/ontology/o the first time it is
saved. Every term minted afterwards is then named after a folder on one particular computer, so two
people mint different IRIs for the same concept and never converge - which makes such a project
precisely the wrong thing to collaborate on.
The wizard rejects a relative base IRI for this reason, so a project generated by OntoBoard today
cannot repeat it. To repair an older one, either generate it again with Tools → New ODK Project…
and an absolute base IRI (http://purl.obolibrary.org/obo/<id>.owl, or your own domain such as
https://w3id.org/<id>), or, to keep the folder: set the ontology IRI to an absolute http IRI in the
Active ontology tab, save, then make uribase: in <id>-odk.yaml and the Prefix(...) lines in
<id>-idranges.owl match. Entities already minted under the bad IRI have to be renamed; if there
are none, there is nothing to migrate.
A stale entry in the sidecar needs no attention - it is pruned automatically, with a line in the log saying so.
A note on what this document used to claim¶
Everything under Editing below says an edit in one window reaches the other. Until OntoBoard 1.50.0 none of it did, and this document asserted it anyway.
Live collaboration was inert in every earlier release: collab/server.mjs resolved a board by
calling openDirectConnection on the Server wrapper instead of the Hocuspocus instance it
holds, so the bridge refused every connection with could not open board and no Protégé peer could
join. Two further defects sat behind it - a rename never reached a peer, and the
different-ontology warning could never fire.
Anyone who followed these steps would have got as far as step 4 and seen a refusal. That nobody reported it is the evidence that nobody did.
The steps below are now executed by two test suites on every build - CollabLiveTest from the Java
side and collab/__tests__/server-boot.test.mjs from the JavaScript side - and the pizza project's
reports/v5/collaboration.md is produced by opening a socket, so it and this document cannot drift
apart without one of them failing.
1. Start the bridge¶
Only the collaboration service is needed. It stores no ontology, so it needs no database.
cd collab
npm install # once
SECRET_KEY=local-test-secret BRIDGE_PORT=1235 COLLAB_PORT=1234 node server.mjs
You should see:
[collab] Hocuspocus server running on port 1234
[collab] JSON bridge for non-JS clients on port 1235
Leave it running. It prints a line each time somebody joins or leaves, which is the quickest way to tell whether a connection got as far as authenticating.
2. Mint two tokens¶
The bridge only checks that a token is signed with SECRET_KEY and takes the user's name from its
sub claim. The backend is not involved, so two tokens can be made directly:
cd collab
SECRET_KEY=local-test-secret npm run --silent mint-token -- alice
SECRET_KEY=local-test-secret npm run --silent mint-token -- bob
Keep both. The name beside a cursor comes from sub, not from anything you type in Protégé —
the bridge sets it once at connect from the authenticated user and ignores what a client claims
afterwards. Two tokens with the same sub would give you two cursors both labelled the same.
The default is 30 days; --days 1 is plenty for an afternoon of testing.
3. Start two Protégé instances¶
Launch Protege.exe twice. Two instances run happily side by side, with two caveats:
- They share
~/.Protege. Preferences and the log are common, so the second instance to save collaboration settings overwrites the first's stored copy. It does not matter while both are running — each holds its own settings in memory — but it means the colour you pick in the second window is the one that persists. - They share the log file.
~/.Protege/logs/protege.loginterleaves both, so timestamps are how you tell them apart.
Open the same project in both - the pizza project this repository builds end to end is a good one: pizza-edit.owl. Both instances editing one file on disk is fine for
this test, because neither writes until you save — but do not save from both, or the second
save overwrites the first. The point of the test is that changes travel through the bridge, not
through the file.
4. Connect both¶
In each window, on the OntoBoard tab (Window → Tabs → OntoBoard), press Collaborate… on the board's toolbar.
| Field | Window A | Window B |
|---|---|---|
| Server address | ws://127.0.0.1:1235 |
ws://127.0.0.1:1235 |
| Board id | pizza-test |
pizza-test |
| Access token | alice's token | bob's token |
| Your colour | pick one | pick a different one |
Leave Remember the token unticked — it is a credential, and for a test there is no reason to write it to the registry.
Both status bars should read Collaborating as alice on pizza-test and Collaborating as bob on
pizza-test. The bridge log should show two joins - [bridge] alice joined 'pizza-test'. If it
shows a refusal instead, the message names the reason; an unauthenticated peer is refused rather
than admitted as nobody, deliberately.
One account is fine. Two windows using alice's token for both now see each other — echo is
filtered per connection rather than per account. You will just have two cursors labelled alice,
which makes the test harder to read, so two names are better.
5. What to test, and what to expect¶
Work down this list. The right-hand column is honest about what is not built yet — a blank result there is not a bug.
Cursors and presence¶
| Try this | Expect |
|---|---|
| Move the mouse over A's canvas | A cursor labelled alice moves on B's canvas |
| Stop moving for 30 seconds | The cursor stays — a heartbeat re-sends it every 3s |
| Select a class in A's tree | A ring in alice's colour appears round that node on B |
| Close A | alice's cursor disappears from B within ten seconds |
| Stop the bridge | Both status bars say Disconnected …; retrying in Ns, cursors vanish |
| Restart the bridge | Both reconnect on their own |
Editing¶
Add a class in A and watch B. Everything here goes through Protégé's OWLModelManager, so it also
appears in B's class hierarchy, not just on the canvas.
| Edit in A | Reaches B | Notes |
|---|---|---|
| New class (double-click the canvas) | yes | With its position |
| New class (Protégé's own + button) | yes | Published from the change listener, so any editor counts |
Rename via rdfs:label |
yes | Broken until 1.50.0: a label travels as a nested field and the inbound reader flattened it to a string, so the operation arrived and did nothing |
| Drag a class from the hierarchy onto the canvas | no | Canvas membership is per-person by design; the entity itself already exists on both |
| Draw a relation (existential) | yes | The reading is preserved — only stays only |
| Subclass axiom | yes | |
| New individual, and its type | yes | |
| Delete a class | yes | Also retracts axioms mentioning it, as Protégé's own delete does |
| Delete an individual | no | The shared vocabulary has no removeIndividual; the status bar will say 1 change not shared |
Equivalent classes, disjointness, owl:hasKey, domain/range, property characteristics |
no | Counted in the status bar with the reason in its tooltip |
| Undo (Ctrl+Z) in A | yes | Undo produces real changes, so they publish like any other |
Watch the status bar. N changes not shared is the feature working correctly, not failing — hover it
for which axiom kind it was.
Not built yet¶
These are in the plan, not in the build. Testing them will find nothing:
- Threaded comments and @mentions — no reply threads and no comment operation in the shared vocabulary. Terms → Discussion link… points at an issue tracker instead, which is where an OBO project's discussion usually lives anyway.
- Sticky notes and frames, live — they are built and drawn: right-click the canvas for
Add note or Add frame, and both are editable in place. What they do not do is travel through
the live session. They live in the sidecar rather than in the ontology - deliberately, since a
diagram annotation is not an axiom and has no business in a release - so they reach a colleague
when the sidecar is committed, not as you type. An inbound
addStickyNotefrom a web client is logged and ignored, which is why that log line exists. - Entity locking — advisory locking is in neither the plugin nor the web app.
Three items that used to be on this list now ship, and testing them will find something:
- Editorial notes — Terms → Note on the selected term… and Terms → All notes… write and list
IAO:0000116editor notes andIAO:0000232curator notes. They travel live, asupdateAnnotation. - Provenance — OntoBoard → Record who edits terms… stamps
dcterms:contributorand a date;EditWatcherattributes what you change. - Release — Build and release → Release… runs the build and stamps
owl:versionIRI, and Build and release → Compare releases… diffs two of them term by term.
What the remaining ones need is in the provenance and release requirements analysis, an internal design document.
Resilience worth checking¶
| Try this | Expect |
|---|---|
| Wrong token | invalid token: … and no retry loop — check the bridge log shows one connection |
ws://127.0.0.1:1234 |
Refused before a socket opens, with a message about 1235 |
| Kill the bridge, edit in A, restart the bridge | A's edits arrive at B when it reconnects — up to 200 are queued |
| Different board ids | Nothing crosses; no error either, because a board id is free text |
| Same board id, different ontologies open | A warning naming the other person. This is the one worth trying deliberately: nothing local can detect it, and without the warning each of you applies the other's axioms to an unrelated file in silence |
6. Reading the log¶
~/.Protege/logs/protege.log, searching for OntoBoard. Lines worth knowing:
OntoBoard: adopted the layout shipped with this version (…) tab layout updated after an upgrade
OntoBoard: dropped 1 canvas entry for entities no longer … stale sidecar entry pruned
OntoBoard: … describes '…' but the open ontology is '…' sidecar belongs to another ontology
OntoBoard: ignoring addStickyNote(…) - … an operation this version cannot apply
The bridge's own log is on its terminal: [bridge] alice joined 'pizza-test'.
7. Tearing down¶
Ctrl+C the bridge. Nothing persists server-side — the operation log lives in memory only, so the next run starts clean. In Protégé, Collaborate… becomes Disconnect.
If you ticked Remember the token, clear it by opening the dialog and unticking — that erases what was written rather than just not writing again.