Date: 2026-09-20
Status: Discovery and design, then built — editors/mdk/ is the plugin (first proposed as
editors/cameo/, renamed when it took the OpenSysML MDK name; §1.2)
Scope: the editors/mdk/ plugin; the Java client (client/java/opensysml-client);
Migrate (internal/translate/xmi, internal/translate/migrate); the results a
Cameo user sees on their own elements
Cameo Systems Modeler (and MagicDraw, Magic Cyber Systems Engineer and Magic Systems of Systems
Architect, which share one platform and one OpenAPI) is where a large share of SysML v1 models
live. OpenSysML already reads those models — OMG UML XMI 2.5 with the SysML profile, and a
MagicDraw/Cameo .mdzip opened in place — and migrates them to SysML v2 notation
(docs/reference/sysml-v1-migration.md); it runs,
verifies and analyzes the result over sysml-grpc, and the Java client wraps every RPC
(docs/reference/java-api.md). The missing piece is the plugin
that lets a Cameo user select a package, choose Run with OpenSysML, and read the verdicts on
their own elements.
This note answers the discovery questions a plugin design depends on, from the vendor's public documentation and Javadoc and from a migration benchmark run over the models that are publicly available, and then proposes the plugin. Every external claim carries the URL it was read from. Claims that could not be confirmed from a public page are marked unverified. No Cameo installation was available: nothing here was run against the tool.
The vendor's current documentation site describes 2026x Refresh1 as the latest release of every CATIA Magic / No Magic product, released on June 26, 2026 (version news). The last release of the previous line is 2024x Refresh3 (2024x Refresh3 version news). The two lines differ in the JDK they ship:
| Release | Bundled / recommended JDK | Source |
|---|---|---|
| 2026x Refresh1 | Eclipse Temurin (AdoptOpenJDK) 21.0.10+7, HotSpot, all OSs | Java version support, 2026x Refresh1 |
| 2026x | Temurin 21.0.8+9 HotSpot, all OSs | Java version support, 2026x |
| 2024x Refresh3 | Temurin 17.0.14 HotSpot | Java version support for 2024x Refresh3 |
Pin: the plugin targets Cameo Systems Modeler 2026x Refresh1 with its bundled
Eclipse Temurin 21.0.10+7 HotSpot — the latest publicly documented release. Every OpenAPI
class the design relies on (§2–§6, §8) is cited from the 2026x Refresh1 Javadoc
(https://jdocs.nomagic.com/2026xRefresh1/) or the current developer guide, and every "no such
OpenAPI class exists" statement below was checked against the 2026x Refresh1 class index
(https://jdocs.nomagic.com/2026xRefresh1/allclasses-index.html).
JDK. The OpenSysML Java client is built to a JDK 17 baseline and documents that on JDK 21
the same code runs unchanged (docs/reference/java-api.md); a
JDK 21 host adds nothing the client needs and removes nothing it uses. The plugin is compiled
with --release 17, so the one jar loads on the pinned JDK 21 and on the JDK 17 of the minimum
release below. It must not use JDK 21 language or library features until the minimum moves.
Minimum supported: 2024x Refresh3 (Temurin 17.0.14), the last release of the previous line.
The v1 path (§2–§6) uses only OpenAPI classes that the 2024x Refresh3 Javadoc
(https://jdocs.nomagic.com/2024xRefresh3/) also lists — each such class is named where it
matters — so the same jar runs there; the SysML v2 path (§8) uses classes that exist only in
2026x and is absent on 2024x Refresh3 by design (§10.1).
A plugin is a directory under the tool's plugins/ folder holding a plugin.xml descriptor,
its jar(s) and any libraries
(Plugin descriptor, current developer guide;
the 2024x Refresh2 page, here,
tabulates the attributes and is unchanged in substance). The fields the design uses:
| Element / attribute | Meaning (from the descriptor page) |
|---|---|
plugin id, name, version, provider-name |
identity shown in the Resource/Plugin Manager |
plugin class |
the fully qualified com.nomagic.magicdraw.plugins.Plugin subclass loaded by the plugin manager |
plugin internalVersion |
integer compared when the same plugin is installed twice |
requires-api |
the OpenAPI version the plugin needs; requires-api="1.0" in the vendor examples |
requires / requires-plugin |
other plugins that must be loaded first (the SysML plugin, for a plugin that reads SysML stereotypes) |
runtime / library name="…jar" |
the jars the plugin's classloader sees |
ownClassloader="true" |
give this plugin its own classloader (default false) |
class-lookup="LocalFirst" |
with ownClassloader, prefer the plugin's copies of classes over the tool's |
PluginDescriptor exposes the same data at run time
(PluginDescriptor, 2026x Refresh1;
also in 2024x Refresh3):
notably getPluginDirectory(), which is how the plugin finds the native sysml-grpc binary it
ships (§2.4).
The abstract class has three methods (Plugin, 2026x Refresh1; Plugin classes, current developer guide):
isSupported()— called first; the plugin is initialized only if it returnstrue. The OpenSysML plugin returnsfalsewhen nosysml-grpcbinary for the host platform is available (§2.4), with a log line saying why, rather than failing later.init()— called at tool start-up; where action configurators, project windows and listeners are registered. It must not start thesysml-grpcchild: the Java client starts one lazily on firstConnectionuse, and an idle child at every Cameo start is what a user would notice.init()only wires UI.close()— called before exit; returningfalsevetoes exit. The plugin closes itsConnections and callsConnection.stopSharedServices(), which ends the child (§12), and returnstrue.
ResourceDependentPlugin is a second interface for plugins that own a profile the project
depends on
(Javadoc).
The OpenSysML plugin writes nothing into the model (§6), so it does not implement it.
All modeling tool plugins (classes and runtime libraries) are loaded by the one classloader. If there are plugins that cannot be loaded by the same classloader … their descriptors should be defined to use own classloaders. — Plugin class loading, 2026x
So by default every plugin shares one classloader. The Java client starts one private
sysml-grpc child per classloader (docs/reference/java-api.md,
"The service binary"). Two consequences:
- If two plugins each shade the OpenSysML client into the shared classloader, the second copy's classes collide with the first's — a plain Java problem, not an OpenSysML one. If they share one copy on the plugin classpath, they share one child and one parse cache.
- The OpenSysML plugin should set
ownClassloader="true"andclass-lookup="LocalFirst". Its dependencies (the client, its protobuf-JSON bodies) then cannot conflict with the tool's or other plugins' versions, and the classloader boundary makes the child's ownership explicit: one plugin, one classloader, one child, closed inPlugin.close().
The tool's own PluginUtils.getPlugins() lists loaded plugins
(Javadoc),
which is how a future second OpenSysML-based plugin could find and reuse this one's connection
instead of starting a child of its own.
Nothing in the vendor's plugin documentation addresses native executables; a plugin directory is
an ordinary directory, so the plugin can lay out binaries however it likes and locate them from
PluginDescriptor.getPluginDirectory(). The Java client resolves the service binary in this
order: ConnectionOptions.binaryPath(...), then $OPENSYSML_GRPC_BINARY, then
~/.opensysml/bin/sysml-grpc (downloading a release pinned by version and verifying its signed
manifest when absent), then $PATH
(docs/reference/java-api.md). The release artifacts are named
sysml-grpc-<goos>-<goarch>[.exe] for linux, darwin and windows
(client/java/opensysml-client/src/main/java/org/openmbee/opensysml/internal/ReleasePlatform.java).
Design: the plugin ships all platform binaries under <plugin dir>/bin/ and passes the one
for the host through ConnectionOptions.binaryPath(...), falling back to the client's download
path only when bin/ is absent (a "thin" build for users whose IT forbids bundled executables
but allows the signed download). Bundling all platforms keeps one Resource Manager .zip
(§2.5) for every OS; the vendor ships one .zip per resource, not per OS.
Two platform facts matter and are recorded as risks (§12): the Java client itself drops the
POSIX execute bit on filesystems that keep none ("Windows and some network filesystems keep no
POSIX mode", BinaryDownloader.java), and a zip extracted by the Resource Manager may not
preserve modes on macOS/Linux — the plugin must chmod +x (Java Files.setPosixFilePermissions)
before first launch. On macOS, an executable extracted from a downloaded zip carries the
quarantine attribute and Gatekeeper may refuse it unless it is notarized — unverified for
this specific path, as the vendor documents nothing about it; the release binary is
sigstore-signed but not Apple-notarized.
Plugins are distributed as a zip whose internal layout mirrors the tool's installation directory
(plugins/<id>/plugin.xml, plugins/<id>/*.jar) plus a resource-manager descriptor at
data/resourcemanager/MDR_Plugin_<id>_<n>_descriptor.xml; the Resource/Plugin Manager
(Help ▸ Resource/Plugin Manager) installs it from a local file, a network share or a web server,
and "supports zip archives only"
(How to distribute resources, 2024x Refresh1;
Creating required files and folders structure, 2024x Refresh2;
Resource Manager, 2024x).
The vendor also offers a Resource Builder wizard (Tools ▸ Development Tools ▸ Build Custom
Resource…) that assembles the same zip. The editors/mdk/ build produces this zip directly
(§8.2), the same way editors/vscode produces a .vsix, and the nightly attaches it beside the
.vsix (docs/project/nightly.md).
Every class in this section is in the 2026x Refresh1 Javadoc. ActionsProvider,
ActionsConfiguratorsManager, BrowserContextAMConfigurator, DiagramContextAMConfigurator,
ProjectWindow and RunnableWithProgress are also listed in the 2024x Refresh3 index
(https://jdocs.nomagic.com/2024xRefresh3/allclasses-index.html), which is what the minimum
release of §1.1 rests on.
Context menus. Actions live in ActionsManagers configured by configurators registered
with ActionsConfiguratorsManager from Plugin.init(). Three interfaces matter
(Creating new actions, 2024x Refresh2;
ActionsConfiguratorsManager, 2026x Refresh1):
BrowserContextAMConfigurator.configure(ActionsManager, Tree)— the containment-tree shortcut menu; registered withaddContainmentBrowserContextConfigurator(BrowserContextAMConfigurator, 2026x Refresh1). TheTreegives the selected nodes, so Run with OpenSysML is offered on aPackage,Class(a Block), aBehavioror aConstraint/Requirement.DiagramContextAMConfigurator.configure(ActionsManager, DiagramPresentationElement, PresentationElement[], PresentationElement)— a diagram's shortcut menu with the selected symbols; registered per diagram type withaddDiagramContextConfigurator(String diagramType, …)(DiagramContextAMConfigurator, 2026x Refresh1).AMConfigurator— main menu and toolbars (addMainMenuConfigurator), for a Tools ▸ OpenSysML menu with Run…, Verify…, Sweep… and Show results.
Actions are MDAction/DefaultBrowserAction/DefaultDiagramAction subclasses added to an
MDActionsCategory; the category, not the action, is what the configurator adds.
ActionsProvider is the other side of the same mechanism: "the singleton class used for
accessing actions in different parts (diagrams, browsers, main menu and etc.)", with
getContainmentBrowserContextActions(BrowserTabTree),
getDiagramContextActions(String diagramType, DiagramPresentationElement, PresentationElement[], PresentationElement)
and getDiagramShortcutActions(...)
(ActionsProvider, 2026x Refresh1).
It reads the configured managers; a plugin contributes through the configurators above and
only needs ActionsProvider to invoke or inspect an existing action (for example, to run the
tool's own Validate after the results are in). The design registers configurators and does
not call ActionsProvider directly.
Docking results panel. ProjectWindowsManager (from
Application.getInstance().getMainFrame().getProjectWindowsManager()) adds a ProjectWindow
— a Swing component described by a WindowComponentInfo (id, name, icon, side, docking state)
— to the active project, and ProjectWindowsManager.ConfiguratorRegistry.addConfigurator(...)
from init() makes its docking state persist with the project
(ProjectWindowsManager, 2026x Refresh1;
ProjectWindow, 2026x Refresh1;
ProjectWindowsConfigurator, 2026x Refresh1).
This is where the OpenSysML Results table (§6) lives, beside the tool's own Validation
Results window. GUILog (Application.getInstance().getGUILog()) is the message/notification
window for one-line status and hyperlinks
(GUILog).
Progress and cancellation. ProgressStatusRunner.runWithProgressStatus(RunnableWithProgress, String description, boolean allowCancel, int millisToShow)
runs a task with the tool's progress dialog; the runnable receives a ProgressStatus and is
expected to poll isCancel()
(ProgressStatusRunner, 2026x Refresh1;
RunnableWithProgress, 2026x Refresh1).
The RPCs are unary, so "cancel" means: stop waiting, discard the answer when it arrives, and —
for a run that will not return — stop the child and start over. The client has one deadline
per connection:
ConnectionOptions.requestTimeout (default 60 s) applies to every RPC made on that
Connection, and no call takes a deadline of its own
(client/java/opensysml-client/src/main/java/org/openmbee/opensysml/ConnectionOptions.java;
docs/reference/java-api.md). A single connection therefore
cannot give Migrate thirty seconds and a run ten minutes, and a cancelled Migrate on a
ten-minute connection blocks for ten minutes. The design opens two connections in the
plugin's classloader with different timeouts: a short one for Migrate and ParseSources,
a long one for execution and verification. Both share the one private child, so the model the
short connection parsed is adopted on the long one by hash (connection.model(model.hash()))
without a second parse. Because the child is reference-counted across connections
(ServiceRegistry.release stops it only when the last connection closes), closing the long
connection alone would leave the child — and the run — alive under the short one's reference;
so the one cancellation path is: call Connection.stopSharedServices(), close both
Connection objects, and recreate both together before the next operation, which pays the
child start and the parse again. A per-call deadline in the Java client would collapse the two
connections into one and is listed as a phase 2 prerequisite (§11). A finer cancel — a
streaming or session RPC — is the surface-parity note's session API
(api-surface-parity.md), not this plugin's to invent.
Diagram highlighting (for step-debug later). Two mechanisms exist. Annotations
(com.nomagic.magicdraw.annotation.Annotation, AnnotationManager) attach a severity, kind,
text and actions to a BaseElement or a PresentationElement; they are runtime-only ("not
stored in the project"), the manager "takes care of drawing decorations around symbols with
annotations", and the caller must update() after adding or removing them and remove them
afterwards (Annotation, 2026x Refresh1;
AnnotationManager, 2026x Refresh1).
A custom AnnotationPainter (Annotation.addPainter) can draw the decoration itself. This is
enough to mark "current state", "fired transition" and "failed constraint" on an open diagram
without touching the model. The second mechanism — the Simulation Toolkit's own animation of
active states and tokens — is not in the OpenAPI class index (its public classes are the
SimulationProfile stereotype constants and SimulationManager/SimulationHelper, which
drive its engine); reusing that animation for a foreign engine is unverified and assumed
unavailable.
The user-facing exporters are File ▸ Export To ▸ UML XMI 2.5 file, Eclipse UML2 (v2–v5)
XMI, MOF XMI, EMF Ecore and MagicDraw Native XML
(Exporting UML models, 2024x Refresh2).
Of these, only the Eclipse UML2 exporter is in the OpenAPI:
BaseEmfUml2XmiPlugin.exportXMI(Project, String destinationDir[, ProgressStatus]) and
exportModel(Project) on the versioned EmfUml2XmiPlugin singletons
(BaseEmfUml2XmiPlugin, 2026x Refresh1;
v4 EmfUml2XmiPlugin).
It writes to a directory, not to memory, and it writes the Eclipse UML2 dialect — which
OpenSysML reads (Papyrus .uml), but with the SysML profile in the Eclipse namespace and the
whole project, not a selection. No OpenAPI entry point for the "UML XMI 2.5 file" exporter was
found in the 2026x Refresh1 class index — the com.nomagic.magicdraw.export package there
holds image export only, and com.nomagic.persistence.XmiExporterDescription describes a
format's version and required resources rather than performing an export. Treat "export
selected package as OMG XMI 2.5 without a dialog" as unverified / not available.
ProjectsManager (Application.getInstance().getProjectsManager()) offers what the native
format needs
(ProjectsManager, 2026x Refresh1):
saveProject(ProjectDescriptor, boolean silent)— saves the project to the descriptor's location;ProjectDescriptorsFactory.createLocalProjectDescriptor(Project, File)makes a descriptor for an arbitrary file (ProjectDescriptorsFactory).exportModule(Project, Collection<Package> packages, String description, ProjectDescriptor)— "Export local (not teamwork) module into given descriptor": a subset of packages written as a.mdzipof its own.
Whether saveProject to a different file re-points the open project at that file (as
"Save As" does) is unverified; exportModule does not have that problem and is the
primary route for a selection.
OpenSysML opens a .mdzip in place and reads its com.nomagic.magicdraw.uml_model.model
entries as one document; profile-application and stereotype classification only trust the OMG
namespaces (http://www.omg.org/spec/UML/…, …/SysML/…) and Papyrus's
(docs/reference/sysml-v1-migration.md). The benchmark
(§9) settles the namespace question empirically: DocGen.mdzip, a Cameo project saved by the
tool, yields 810 mapped and 388 approximated entries out of 1907 — Blocks, value properties,
requirements and constraints are recognized — so the native .mdzip carries SysML stereotype
applications in the OMG namespace, as the vendor's save format is itself XMI with the standard
profiles. No in-memory step is needed, and the export the plugin performs is:
selection (packages) → ProjectsManager.exportModule(project, packages, "OpenSysML run", tmp.mdzip)
whole project → ProjectsManager.saveProject(createLocalProjectDescriptor(project, tmp.mdzip), true)
(or, when the project is already saved locally and clean, its own file)
tmp.mdzip → Connection.migrateFile(tmp.mdzip, "sysml") (file_path over the wire)
MigrateRequest.file_path is read by the sysml-grpc child, which runs on the same machine as
Cameo, so a temporary file is enough. Inline content with from_format: "xmi" is also
accepted by the service (a conformance case parses vehicle.xmi inline), and is the route for
an XMI text a future exporter API produces — but a .mdzip is a zip and content is a string,
so the archive goes by path.
Two limitations carry over from the migration reference: elements of used projects
(modules) are not loaded, so references into them stay unmapped — the plugin should export the
used modules too and pass every file to Migrate once the service accepts several sources
for one migration (§11, phase 3); and Teamwork Cloud projects have no local .mdzip, so saveProject
to a local descriptor (or exportModule) is the only route for them.
Cameo side. Every BaseElement has getID(), the persistent element ID that is the
xmi:id in the saved project; Element.getHumanName() and getQualifiedName() on
NamedElement give the display and qualified names. (The Javadoc for BaseElement.getID() was
not fetched; that getID() is the persisted xmi:id is the vendor's long-standing contract and
is verified only indirectly here — the .mdzip fixtures under tests/migrate/testdata/xmi
and the benchmark archives carry xmi:id values in MagicDraw's _18_0_… form, and the report
records them as id.)
OpenSysML side. The migration report is the per-element accounting
(internal/translate/migrate/report.go): one Entry per source element with
| field | content |
|---|---|
id |
the source xmi:id |
kind |
the applied stereotype(s) or UML metaclass, e.g. «Block» Class |
name |
the source qualified name |
target |
the v2 qualified name the conversion wrote, when it wrote one |
verdict |
mapped, approximated, unmapped, skipped |
note |
why, for anything but mapped |
with Report.Source, an optional Exporter (read from xmi:Documentation), and Count(),
Unreferenced() and Summary() over the entries. id → target is exactly the map the
plugin needs: a verdict OpenSysML reports on Demo::Vehicle::massLight is looked up by
target, and the entry's id is the Cameo element to annotate. Elements the conversion
renamed (duplicate member names, reserved words — the migration reference lists the cases as
approximated) are still found this way, which is why the plugin must never reconstruct the
name itself.
What the service returns today. MigrateResponse carries the report: its summary and
counts always, and every entry (id, kind, name, target, verdict, note) when
MigrateRequest.report is set
(docs/reference/sysml-v1-migration.md;
api/proto/sysml.proto, MigrationReport). The Java client hands it over as
Migration.report(). The plugin surfaces the summary as a diagnostic of the run but does not yet
read the entries, so it still matches by name and loses renamed elements; §11 makes reading them
the prerequisite of the results UI's identity map.
Three vendor mechanisms, used together:
- Annotations (§3) — a runtime
Annotation(severity, kind, text, target)per verdict,AnnotationManager.update(removed, added), and the tool draws the decoration on every diagram symbol of the element and in the browser. Severity is anEnumerationLiteralof the tool's severity enumeration (Annotation.ERROR/WARNING/INFOname the kinds); a failedassert constraintis an error, a requirement not satisfied a warning, a holding verdict an info that is off by default. Annotations carryNMActions, so each decoration offers Show in OpenSysML Results and Re-run. - The Validation Results window —
ValidationHelper.openValidationWindow(ValidationRunData, String windowID, Collection<RuleViolationResult>)"opens validation window and displaysRuleViolationResultin it" (ValidationHelper, 2026x Refresh1; ValidationRunData, 2026x Refresh1). ARuleViolationResultpairs anAnnotationwith theConstraint(a validation rule) it violates, so this route needs a rule element in the model — an OpenSysML validation suite profile with one rule per verdict kind (constraint failed, requirement unsatisfied, run error) shipped as a read-only module. It buys the tool's own grouping, filtering, and "select in browser/diagram" for free. (com.nomagic.reportwizard.tools.validation.ValidationResultis the Report Wizard's object, not this one.) - A custom results panel (§3) — the
ProjectWindowtable with columns the validation window lacks: engine (run,explore,solve,sweep), answer strength, schedule seed, replay command, sweep row; double-click selects the element (SelectionUtilities/Application.getInstance().getMainFrame().getBrowser()), and Copy assysmlcommand gives the replayable CLI line.
Verdicts arrive from the Java client as Verification (constraint/requirement, with
verdict, bounded, the checked object's instancePath), Satisfaction (every
assert satisfy), Validation (every constraint of one object) and Sweep rows
(docs/reference/java-api.md, Verification and Parameter
sweeps). Each names the v2 element; §5 maps it back.
Magic Model Analyst / Cameo Simulation Toolkit is "an extendable model execution framework based on OMG fUML and W3C SCXML standards" that executes, animates and debugs SysML models, including parametrics, with mock-up user interfaces (documentation home, 2026x). Specifically:
- fUML 1.3 activity semantics, with the action kinds it supports enumerated (Activity simulation engine, 2026x).
- State machines on W3C SCXML semantics (per the home page above). PSSM conformance is not claimed on any page found; treat "PSSM" as unverified for the Toolkit. PSCS conformance likewise unverified; composite-structure behavior (ports, connectors, flows) is simulated, but no page found names the PSCS specification.
- Parametrics: a built-in math solver (Octave-like syntax) as the default parametric evaluator, plus external evaluators — MATLAB, Mathematica, Dymola — and scripting languages (Built-in Math; Integration with external Evaluators, 2026x; Specifying the language for the expression). The solver evaluates; it does not search for values that satisfy a constraint set.
- Alf comes from the separate Alf Plugin, which compiles Alf to fUML activities that the Toolkit executes ("Full Conformance" level) (Alf Plugin, 2026x; Running a model with Alf, 2024x Refresh3).
- Recent additions are the HTML UI, the Result Player, server-side simulation, and Modelica export; "certain outdated integrations have been discontinued" in 2026x (2026x version news for the Toolkit).
The Toolkit is the interactive simulator of the SysML v1 model as drawn: animation, mock-up UIs, external solvers, timelines. OpenSysML executes the v2 model that the migration (or, for v2 projects, the textual export — §8) produces, and adds what the Toolkit has no counterpart for:
| OpenSysML capability | Where it is described | Toolkit counterpart |
|---|---|---|
Deterministic, replayable schedules — every unordered choice recorded as a choice point; declared / seed:<n> replay; explore enumerates every linearization within a budget |
scheduling.md, region-order-scheduling.md |
none: one interactive run at a time; no page found describes replaying a schedule |
Batch verification — VerifyConstraint, VerifyRequirement, VerifySatisfaction, ValidateInstance over a whole model in one call, no UI |
api/proto/sysml.proto; java-api.md |
validation suites check well-formedness, not requirement satisfaction under execution |
RunSweep — a parameter grid or sample, one row per run with inputs, outputs and verdicts |
java-api.md, Parameter sweeps |
none found (the Toolkit runs one configuration; trade studies are a separate product) |
SMT-backed constraint solving — the solve engine finds values satisfying a constraint set, and the bounded model checkers ask a solver whether any schedule violates a requirement |
analysis-framework.md, smt-model-checking.md |
the parametric evaluators compute a value from given inputs; they do not solve for unknowns |
RDF export — Convert to Turtle; OSLC-shaped Query |
docs/reference/rdf-mapping.md |
none |
| Answer strength — proved / bounded / witnessed / observed / not covered on every result | analysis-framework.md |
none |
What OpenSysML does not offer and the plugin must not pretend to: diagram animation of the v1 model, mock-up UIs, MATLAB/Mathematica/Dymola evaluators, and Alf. A user with a Toolkit-dependent model keeps using the Toolkit; the OpenSysML plugin sits beside it for batch, sweep, solve and replay.
The pinned release, 2026x Refresh1, ships a SysML v2 Plugin with a SysML v2 project type, a textual editor and two-way synchronization between text and diagrams, a SysML v2 Evaluation Plugin for static evaluation, and a free Community Edition capped at 500 elements (SysML v2 Plugin documentation, 2026x; CATIA Magic/Cameo SysML v2 Solution). SysML v1 and v2 are chosen per project, in one installation (same page). Concretely:
- Textual import/export in the UI: File ▸ Export To ▸ SysML v2 Textual Notation writes
selected root namespaces as
.sysmlfiles — "You can export SysML v2 project namespaces into .sysml textual notation files which you can later import into your projects" — and File ▸ Import From ▸ SysML v2 Textual Notation imports a.sysmlfile into a separate root namespace (Textual notation import/export, 2026x Refresh1). - Textual import/export in the OpenAPI (2026x Refresh1):
SysMLTextualNotationService.exportTextual(Namespace) → StringandimportTextual(ModelElementProject, String)(Javadoc), andSysMLProjectHelperto create or open v2 ("UPS") projects (Javadoc). The v2 metamodel is a separate API (com.dassault_systemes.modeler.kerml.model.kerml.Namespace, thecom.dassault_systemes.modeler.sysml.libraries.standard.*library classes), not the UMLElementtree. - Their own v1→v2 transformation (File ▸ Export To ▸ SysML v2 Model) is "a work in
progress": the 2026x Refresh1 page says it covers "over 80% of the SysML v1 to SysML v2
Transformation specification", where the 2026x page said "about 20% of the metamodel"; it
writes an
.xlsxof not-migrated elements and does not migrate diagrams (Performing SysML v1 to v2 model transformation, 2026x Refresh1; Migration from SysML v1 to SysML v2, 2026x). The two percentages measure different things (a specification's clauses versus the metamodel) and are not comparable with each other or with the benchmark in §9.
Consequence. On the pinned release the plugin has two front ends and one engine:
| Project kind | How the model reaches OpenSysML | Identity map |
|---|---|---|
| SysML v1 | .mdzip → Migrate(xmi→sysml) → ParseSources (§4) |
migration report id → target (§5) |
| SysML v2 (SysML v2 Plugin installed) | SysMLTextualNotationService.exportTextual(root) → ParseSources — no migration |
v2 qualified names are the same on both sides; OpenSysML's Symbol answers carry them |
For v2 projects the vendor's parser is the one the user authored against and OpenSysML is a
second parser and the execution engine of the same text; disagreements between the two
parsers are themselves findings (the Diagnostics from ParseSources land in the results
panel). Whether exportTextual emits element IDs as comments or @id metadata that would give
a stronger identity than names is unverified.
A third route exists for v1 projects on the pinned release — the vendor's own transformation
to a v2 project, then exportTextual — and the design does not take it as the primary
path: the transformation is a user-driven export that produces a second project, its
not-migrated list is an .xlsx rather than a per-element map, and nothing ties a v2 element it
creates back to the xmi:id of the v1 element, so verdicts could not land on the user's v1
elements (§5–§6). OpenSysML's own migration keeps that map. The vendor route is offered as an
opt-in ("Run the SysML v2 project instead") for users who have already transformed, and its
coverage is compared with §9 in the first licensed run (§10.3).
On the minimum release, 2024x Refresh3, no SysML v2 project type or .sysml import was
found: its version news
(2024x Refresh3 Version News)
announces none, and its Javadoc index lists no com.dassault_systemes.modeler.magic.sysml.textual
or .core package, only a handful of diagram classes under com.dassault_systemes.modeler.magic.
Treat "2024x Refresh3 has no SysML v2 support" as unverified (not found) rather than
established. There OpenSysML is the only SysML v2 parser the plugin has and every model reaches
it through the v1 migration (§4–§5). Because the v2 front end's vendor types are absent on the
minimum release, it is a separate module loaded by reflection or a second plugin (§10.1), and
its isSupported() checks for the SysML v2 Plugin.
Question. Is Migrate from v1 XMI/.mdzip good enough to be the plugin's primary path
for v1 projects?
Method. OpenSysML built with make build. Twenty models were gathered: the ten fixtures
under tests/migrate/testdata/xmi/, seven Papyrus SysML 1.1 test models
(github.com/bmaggi/Papyrus-SysML11, tests/…/model/*.uml and samples/*.uml), two Cameo
.mdzip projects from Open-MBEE's MDK (github.com/Open-MBEE/exec-cameo-mdk:
src/main/dist/samples/MDK/DocGen.mdzip, src/test/resources/CSyncTest.mdzip), and the OMG
SysML 1.6 profile itself (https://www.omg.org/spec/SysML/20181001/SysML.xmi; a profile, not a
user model, included as the only OMG XMI artifact that resolved). For each:
bin/sysml <model> -migrate sysml -o <out>.sysml -migration-report <out>.report.json
bin/sysml <out>.sysml -validate-validate is the CLI's check-and-exit flag (bin/sysml -h; there is no -check flag).
Diagnostics were counted as lines matching error: and warning: case-insensitively, excluding
the no errors summary. Attempts that did not resolve, so the set is what it is:
github.com/eclipse-papyrus/org.eclipse.papyrus-sysml16 and …-sysml11 (404),
github.com/Open-MBEE/mms-test (404), the bmaggi/SysML14-Gendoc-Example model (listed by
the API, raw download 404), https://www.omg.org/spec/SysML/1.6/SysML.xmi (404). No vendor
sample .mdzip is downloadable without an installation.
Results. Every migration and every validation exited 0; no panics, no error:
diagnostics on any migrated model.
| file | source | entries | mapped | approx. | unmapped | skipped | check errors | check warnings | top unmapped kinds |
|---|---|---|---|---|---|---|---|---|---|
acquisition.xmi |
repo fixture | 65 | 52 | 5 | 6 | 2 | 0 | 0 | DurationObservation (6) |
heater_receptions.xmi |
repo fixture | 81 | 69 | 10 | 2 | 0 | 0 | 0 | Parameter, Reception |
meter.xmi |
repo fixture | 130 | 97 | 33 | 0 | 0 | 0 | 0 | — |
plant.xmi |
repo fixture | 62 | 56 | 6 | 0 | 0 | 0 | 0 | — |
plant_states.xmi |
repo fixture | 112 | 103 | 5 | 3 | 1 | 0 | 3 | TimeEvent, Trigger |
ported_calls.xmi |
repo fixture | 53 | 45 | 8 | 0 | 0 | 0 | 0 | — |
reactor.xmi |
repo fixture | 79 | 56 | 23 | 0 | 0 | 0 | 0 | — |
rig_interactions.xmi |
repo fixture | 88 | 75 | 6 | 6 | 1 | 0 | 0 | Interaction (3), MessageOccurrenceSpecification (2) |
simconfig.xmi |
repo fixture | 38 | 30 | 6 | 2 | 0 | 0 | 0 | Slot (2) |
vehicle.xmi |
repo fixture (exporter "Example UML Tool") | 95 | 78 | 11 | 3 | 3 | 0 | 2 | «Unit», «QuantityKind» InstanceSpecification |
DocGen.mdzip |
Cameo, Open-MBEE MDK | 1907 | 810 | 388 | 336 | 373 | 0 | 28 | Constraint (123), «Viewpoint» Class (116) |
CSyncTest.mdzip |
Cameo, Open-MBEE MDK | 9 | 6 | 2 | 0 | 1 | 0 | 0 | — |
SysML_Allocate_TEST.uml |
Papyrus 1.1 | 12 | 1 | 8 | 0 | 3 | 0 | 0 | — |
SysML_DeriveReqt_TEST.uml |
Papyrus 1.1 | 12 | 1 | 8 | 0 | 3 | 0 | 0 | — |
SysML_Satisfy_TEST.uml |
Papyrus 1.1 | 13 | 1 | 9 | 0 | 3 | 0 | 0 | — |
SysML_Verify_TEST.uml |
Papyrus 1.1 | 16 | 1 | 5 | 7 | 3 | 0 | 0 | «TestCase» (4), «Verify» Abstraction (3) |
ModelWithBDD.uml |
Papyrus 1.1 | 12 | 1 | 0 | 0 | 11 | 0 | 0 | — |
ModelWithIBD.uml |
Papyrus 1.1 | 13 | 1 | 1 | 0 | 11 | 0 | 0 | — |
ModelWithPD.uml |
Papyrus 1.1 | 14 | 1 | 2 | 0 | 11 | 0 | 0 | — |
SysML.xmi |
OMG profile | 2 | 0 | 0 | 1 | 1 | 0 | 0 | Tag |
Reading it.
- On Cameo's own format the classifier works.
DocGen.mdzip— a real, 1907-entry Cameo project — converts with 63 % of entries mapped or approximated and validates with no errors. Its unmapped entries are dominated by two kinds that are out of scope for execution: 122Constraints whose specification is a UMLExpressiontree ("a UML Expression tree has no v2 form") and 116 «Viewpoint» classes plus «Expose» dependencies ("viewpoints are not migrated yet") — DocGen is a document-generation profile, not a system model. The 28 warnings are allDuplicate of inherited member namefrom generalizations the migration kept. The 373 skipped entries are profile applications, imports and notation, as the report'sUnreferenced()separates them. - On system models, the fixtures, 80–95 % of entries map cleanly, the remainder are
approximated with a note (return parameters as
out, untyped properties as reference usages, partitions as comments), and the unmapped kinds are exactly what the migration reference lists as not yet migrated: interactions, duration observations, time events, units. The threeplant_stateswarnings are OpenSysML's own extension notice forhistory/junctionpseudostates it wrote (pseudostates.md) — a fact about the target notation, not a migration loss. - The Papyrus 1.1 rows are a namespace finding, not a migration finding. Those files
declare
xmlns:uml="http://www.eclipse.org/uml2/3.0.0/UML"and the 2010-era SysML profile namespace, which the reader does not recognize (it accepts the OMG namespaces and Papyrus SysML 1.6's); every element but the root is skipped as an unrecognized profile application. Papyrus 1.6 samples would have been the fair test; none resolved. A Cameo plugin never sees this dialect. - Units are not migrated («Unit»/«QuantityKind» instance specifications in
vehicle.xmi), as the migration reference states; a v1 model whose constraints depend on unit conversion evaluates differently until they are.
Verdict. For a v1 system model saved by Cameo, Migrate is good enough to be the primary
path: it never fails, every element is accounted for with a verdict and a note, and what is lost
(interactions, viewpoints, units, expression-tree constraints) is nameable and shown to the user
per element rather than silently dropped. The plugin must present approximated and unmapped
counts before the first run (the pre-flight in §10.4) so the user knows what the engine did not
see; that is the report-over-service prerequisite of §11, phase 3. The benchmark's weakness is
its sample — two Cameo projects, neither a behavioral system model; the plugin's first
integration test against a licensed Cameo (§10.3) should migrate the vendor's bundled samples
(samples/SysML/*.mdzip in an installation) and re-run this table.
editors/mdk/
README.md build, licence-free CI, model paths, distribution, the DocGen bridge
pom.xml Maven reactor; Java 17; pins the OpenSysML client version
plugin/ the plugin — compiles with --release 17 against the 2026x Refresh1
OpenAPI, using only classes also present in 2024x Refresh3 (§1.1)
src/main/java/org/openmbee/opensysml/mdk/
OpenSysMLPlugin.java Plugin: isSupported / init / close; the docGen facade (§14)
actions/ OperationActions configurator, one MDAction per Operation,
CalcArguments, the DocGen stereotype installer action
annotations/ AnnotationPlanner / Annotations: results → validation annotations
bin/ HostBinary: sysml-grpc resolution from the plugin directory
bridge/ DocGenBridge: the facade's implementation (§14)
docgen/ DocGenExtensions: creates the «JavaExtension» stereotypes
engine/ Engine, Operation, RunRequest: the two Connections (§3)
identity/ IdentityResolver: v2 qualified name → Cameo element
results/ RunResult and the outcome/diagnostic model
selection/ SelectionResolver, Selection: what was right-clicked
source/ ModelSource: .mdzip export or v2 textual export
ui/ ResultsWindow (ProjectWindow)
mdk-bridge/ the DocGen «JavaExtension» queries MDK loads (§14); depends on
neither the client nor the plugin at run time
openapi-stubs/ compile-only stubs of the OpenAPI classes the plugin touches (§10.3)
mdk-api-stubs/ compile-only stubs of the MDK classes the bridge extends (§14)
tools/ BinaryStager, PluginDescriptorWriter (build-time)
dist/ the Resource Manager .zip
The plugin depends on the published org.openmbee:opensysml Java client
(java-api.md) at the version pom.xml pins; the client is
installed into the local repository first (editors/mdk/README.md).
Gradle (Kotlin DSL), matching the Java client's build rather than Maven; the vendor's own examples are Ant/Gradle. Two source sets need OpenAPI jars on the compile classpath:
- Licensed developer machine:
-PcameoHome=/opt/Cameoputs<cameoHome>/lib/*.jarand<cameoHome>/plugins/**/*.jaron the compile classpath (compileOnly). Nothing from the installation is copied into the artifact. - CI: §10.3.
The distZip task lays out plugins/org.openmbee.opensysml/{plugin.xml,*.jar,bin/*} and
data/resourcemanager/MDR_Plugin_org_openmbee_opensysml_<n>_descriptor.xml and zips it; the
nightly attaches it beside the .vsix with the same <version>-nightly-<date>-<commit> scheme.
The OpenAPI jars are not on Maven Central and the licence forbids redistributing them (the
vendor's public GitHub examples, e.g. the MDK at github.com/Open-MBEE/exec-cameo-mdk, resolve
them from a local installation). Two ways to keep CI honest:
- Compile-only stubs (
openapi-stubs/): hand-written classes with the signatures the plugin calls —Plugin,PluginDescriptor,ActionsConfiguratorsManager, the three configurator interfaces,MDAction/MDActionsCategory,Application,Project,ProjectsManager,ProjectDescriptorsFactory,ProjectWindowsManager,ProjectWindow,WindowComponentInfo,ProgressStatusRunner,RunnableWithProgress,ProgressStatus,Annotation,AnnotationManager,ValidationHelper,ValidationRunData,RuleViolationResult,BaseElement/Element/NamedElement/Package,GUILog. Every stub method body isthrow new UnsupportedOperationException("stub"). The stubs compile the plugin and let its unit tests run against Mockito mocks of the same types; the Javadoc pages cited here are the specification each stub is written from. A stub drifts silently when the vendor changes a signature — so: - A licensed agent for the integration lane: a self-hosted runner with a Cameo installation
and a floating licence runs the same build with
-PcameoHome, which fails to compile if a stub lied, and then runs the plugin headless. Cameo supports headless execution of a plugin throughcom.nomagic.magicdraw.commandline.CommandLine/ProjectCommandLine(Javadoc), which is how the integration test opens each sample.mdzip, runs export → migrate → parse → verify, and asserts the identity map is total over the report'smappedentries. This lane is optional and non-blocking for outside contributors, and required for release. Whether the vendor's licence terms permit an unattended CI seat is unverified; a maintainer with the licence agreement must confirm before the lane exists.
user: right-click Package P (or a Block, Behavior, Requirement) ▸ OpenSysML ▸ Run…
1 configurator resolves the selection to packages, or the owning package of a single element
2 ProgressStatusRunner.runWithProgressStatus(task, "OpenSysML", allowCancel=true, 0)
3 task, phase "export": Exporter → tmp/<project>-<hash>.mdzip (exportModule / saveProject)
4 task, phase "migrate": Migration c = connection.migrateFile(tmp, "sysml")
c.experimentalNotice → GUILog once per session
c.report.summary → results panel
pre-flight: c.report → counts (mapped/approximated/unmapped) and the
unmapped kinds; shown in the panel header; user may stop here
5 task, phase "parse": Model m = connection.parseSources(List.of(SourceDocument.inline("model.sysml", c.content())))
parse diagnostics → results panel (a v1 model that migrates but does
not parse is a migration bug to report upstream — its .sysml is kept)
6 task, phase "run": per the action chosen:
Run → m.instantiate(target); m.runAction / runState (schedule policy from the dialog)
Verify → m.verifySatisfaction(scope) + verifyConstraint/Requirement per selected element
Sweep → m.runSweep(calc, ranges, options) from a small dialog
each answer's element names → identity map → Cameo elements
7 results: Annotations on the mapped elements; RuleViolationResults into the validation
window (when the suite module is loaded); every row into the OpenSysML Results panel
8 the tmp .mdzip and .sysml are kept under the tool's temp dir until the next run, with a
"Reveal migrated model" action, because the user will want to read what the engine read
isCancel() is polled between phases and the current connection's deadline bounds the wait
inside one (§3: the short connection for phases 4–5, the long one for phase 6). The first run
after start-up pays the child start (the client starts it lazily); later runs
share the parse cache when the exported archive is unchanged (the client hashes sources).
ElementMap is built once per conversion from the report: Map<String xmiId, Entry> and
Map<String target, List<Entry>>; a Cameo Element is fetched by ID with Project.getElementByID(String)
(Project, 2026x Refresh1).
The reverse map is a list because a target is not a unique key: the migration deliberately
writes some source elements into a declaration owned by another — an operation's method
behavior is recorded against the operation's target ("written as the body of the operation",
internal/translate/migrate/behavior.go), and a renamed duplicate member may share a target
with the element it collided with. Answers carry v2 qualified names (Symbol,
Verification.constraintId/requirementId, SweepRow) and are resolved through that list;
when it has more than one entry the result kind picks by Entry.kind, whose vocabulary is the
source's UML metaclass with an optional stereotype prefix (kindOf in
internal/translate/migrate/classify.go writes «Block» Class, Activity, Operation, never
an abstract Behavior): an action or state verdict prefers the entry whose metaclass, after
the «…» prefix, is one of Activity, StateMachine, OpaqueBehavior, FunctionBehavior
or Interaction; a constraint verdict prefers Constraint; a value prefers Property or
Port. When the kind still does not decide, the verdict is linked to every candidate and
the panel shows them all rather than choosing one silently. A normalized target-kind field on
the report entry would replace this string matching and belongs with the report-over-service
change (§11, phase 3). A name with no entry — a
library element, or a name the conversion synthesized — is shown in the panel without an
element link, never dropped.
| Phase | Delivers | Prerequisites in OpenSysML |
|---|---|---|
| 1. Migration-based execution | editors/mdk/plugin skeleton; plugin.xml; browser/diagram/menu actions; export → Migrate → ParseSources → instantiate/run/verify; results in GUILog and a plain table; stubs lane in CI; nightly .zip |
none — everything used is on the wire today |
| 2. Results UI | docking ProjectWindow table; Annotations on elements; validation-suite module and RuleViolationResult bridge; Reveal migrated model; per-phase deadlines and cancel |
none for the UI (two connections give per-phase deadlines, §3; a per-call deadline in the Java client would replace them); identity requires phase 3's report — until then names only |
| 3. Units and report-over-service | pre-flight counts and per-element migration notes in the panel; unit-bearing constraints evaluated correctly | Migrate returns the migration report (MigrateResponse.report, the Entry shape of report.go — on the wire today) and accepts several source files for one migration (used modules); unit migration in internal/translate/migrate |
| 4. Step-debug | step a behavior from Cameo; highlight current state / fired transition / token on the open diagram through AnnotationPainters; choice-point display and reseed |
the debugger session API of api-surface-parity.md on the wire and in the Java client |
| v2 front end (in parallel from phase 1; needs the SysML v2 Plugin on the developer machine) | plugin-v2: exportTextual → ParseSources, no migration; parser-disagreement report; opt-in run of a vendor-transformed v2 project |
none |
The implementation under editors/mdk/ follows §10 with these deviations:
- Maven, not Gradle. The module is a Maven reactor (
openapi-stubs,tools,plugin,dist) so it builds with the same toolchain asclient/java; the client is consumed as an installed artifact rather than an included build.CAMEO_HOME(a shell script, not a Gradle property) compiles the plugin against a licensed installation. - One module for both paths.
plugin-v2is folded intoplugin(org.openmbee.opensysml.mdk.v2) because the SysML v2 classes it needs (SysMLTextualNotationService, KerMLElement,Namespace) are stubbed like the rest of the OpenAPI, so nothing forces a second source set. At runtime the v2 path is taken only when the textual service class loads and the selection is a SysML v2 element; otherwise the selection is exported as a.mdzip. - Identity by qualified name on both paths. The service does not return the migration
report (phase 3), so v1 results are matched by the Cameo qualified name normalized the way the
migration writes it (quoted segments unquoted). Every candidate for an ambiguous name is kept
and annotated; a name the migration synthesized (
unnamed2, renamed duplicates) is shown in the results window without an element link. TheEntry.kindpreference of §10.5 waits for the report. - Actions per operation, not a Run dialog. The context menu group holds six actions
(Instantiate, Execute action, Execute state machine, Verify requirement/constraint, Evaluate
calc, Run analysis), enabled for exactly one selected element; Verify picks
verifyRequirement,verifySatisfactionorverifyConstraintfrom the symbol's kind. Sweep, the schedule dialog and Reveal migrated model are deferred with phase 2's remaining items. - Whole-project export.
exportModuleis given the primary model, since a selected element alone loses the references the conversion needs; a saved, unmodified.mdzipis read in place. - Phase 2's results window and annotations are in phase 1: a docking
ProjectWindowper project with outcomes, diagnostics, final time and schedule, double-click selecting the element in the containment tree, andAnnotations replaced per project on every run. TheRuleViolationResultbridge and the validation-suite module are not. - One connection, cancel by close. A single
Connectionis opened lazily and reused; the progress dialog'sisCancel()is polled every 250 ms and cancelling closes the connection, which aborts the in-flight RPC. The next run reopens it. Per-phase deadlines come from the client's request timeout rather than two connections. - Distribution.
mvn -f editors/mdk/pom.xml -Dopensysml.version=vX.Y.Z packagedownloads the fivesysml-grpcrelease assets, verifies each against the digest table the client jar ships, generatesplugin.xmllisting every runtime jar, and zipsplugins/org.openmbee.opensysml.mdk/withdata/resourcemanager/.
Each item says what is known, what is not, and what would settle it.
- Windows child process.
PrivateServicestartssysml-grpc -exit-with-parent, holds the write end of the child's stdin pipe and never writes; the child exits on end of file, which the kernel delivers when the parent dies. The source states that Windows anonymous pipes give the same guarantee (PrivateService.java, class comment). Two things are unverified on Windows inside Cameo: whether the tool's own process shutdown (a crash, orclose()never called because another plugin vetoed exit and the user killed the process) still closes the handle promptly, and whether a Cameo launched from the vendor's.exelauncher inherits handles in a way that leaves a second holder of the pipe. Settle by: a licensed Windows integration run that killscsm.exeand asserts nosysml-grpc.exeremains after a few seconds. Mitigation if it fails: the child's-exit-with-parentgains a parent-PID poll on Windows. - Executable bits and quarantine. Resource Manager extraction may not preserve POSIX modes;
macOS Gatekeeper may refuse an un-notarized binary from a downloaded zip (§2.4, unverified).
Settle on licensed macOS/Linux runs; mitigation:
chmodbefore launch, and documentxattr -d com.apple.quarantineor ship notarized binaries. - No OpenAPI OMG-XMI exporter. The design relies on
.mdzip(§4.2). IfexportModulerefuses packages that reference elements outside the selection, orsaveProjectto a new descriptor re-points the open project, the export falls back to saving the whole project to a temp file and passing the selection asParseOptions/scope to OpenSysML instead. Settle with a licensed run. - Migration report not on the wire (§5). Without it the identity map is by name and renamed elements are lost; phase 2's per-element results are only as good as names.
- Used projects / Teamwork Cloud. Modules are not loaded by the reader; a TWC project has
no local file. Both need the multi-source
Migrateof phase 3 and a licensed TWC test. - Units. Not migrated; a model whose constraints depend on unit conversion is wrong, not
just approximate, until
internal/translate/migratehandles «Unit»/«QuantityKind». - Two JDKs, two API surfaces. The pinned 2026x Refresh1 runs the plugin on JDK 21, the
minimum 2024x Refresh3 on JDK 17;
--release 17covers both and the Java client's JDK 17 baseline runs unchanged on 21 (§1.1). Theplugin-v2module's vendor types exist only on the 2026x line, so it must be loaded reflectively or shipped as a second plugin withrequires-pluginon the SysML v2 Plugin. Dropping the minimum release later removes the split. - Licence terms for CI (§10.3): unverified whether an unattended seat is permitted.
- Simulation Toolkit conformance claims (§7.1): PSSM and PSCS conformance are not claimed
on any page found; the positioning table says "SCXML-based state machines" and no more. If a
page is found, the alignment note (
precise-semantics-alignment.md) is the place to compare. - Vendor
.mdzipsamples untested. The benchmark's Cameo rows are two Open-MBEE projects; the vendor's bundled samples were not available. First licensed run re-does §9 over them.
- That the Resource Manager preserves the POSIX execute bit when extracting a plugin zip on
macOS/Linux (§2.4) — the design
chmods regardless. - macOS Gatekeeper behaviour for a
sysml-grpcbinary extracted by the Resource Manager (§2.4). - Reuse of the Simulation Toolkit's diagram animation for a foreign engine (§3) — assumed unavailable.
- Any OpenAPI entry point for File ▸ Export To ▸ UML XMI 2.5 file (§4.1) — none found.
ProjectsManager.saveProjectto a new local descriptor leaving the open project's own location unchanged (§4.1).BaseElement.getID()being the persistedxmi:id(§5) — verified only through the fixtures' IDs, not from the Javadoc page.- The Simulation Toolkit's PSSM and PSCS conformance (§7.1).
- That the minimum release, 2024x Refresh3, has no SysML v2 project type or textual import (§8) — not found in its version news or Javadoc index, which is absence of evidence only.
- Whether
SysMLTextualNotationService.exportTextualemits element identity beyond names (§8). - Windows pipe semantics of the child under Cameo's launcher and abnormal shutdown (§12.1).
- Whether the vendor's licence permits an unattended CI seat (§10.3).
OpenMBEE's MDK (Open-MBEE/mdk) is the plugin a large share
of Cameo users already run for MMS synchronisation and DocGen documents. OpenSysML MDK is
positioned as its successor (docs/project/mdk-parity.md
tracks the gap), and the first concrete step is to let an MDK document run OpenSysML.
DocGen's «JavaExtension» stereotype (profile SysML Extensions, URI
http://openmbee.org/mdk/sysml-extensions) tells DocGen to instantiate a Java class — named by
the applied stereotype's name — as a org.openmbee.mdk.model.Query, call setTargets,
initialize, then visit(forViewEditor, outputDir), and splice the returned
DocumentElements into the document. The class is resolved with
Class.forName(name, true, MDKPlugin.extensionsClassloader), a URLClassLoader over every jar
in plugins/org.openmbee.mdk/extensions/ whose parent is MDK's own classloader. This is an
extension point MDK ships for exactly this purpose, so no change to MDK is needed.
The extension classloader cannot see the OpenSysML plugin's jars (ownClassloader="true",
class-lookup="LocalFirst", §2.3), and bundling the Java client, protobuf and the service into
the bridge would mean a second service process and a second copy of every dependency. The
bridge therefore stays small and calls back:
mdk-bridge (MDK's extension classloader) plugin (its own classloader)
<Operation>Query.visit(…)
PluginLocator: PluginUtils.getPlugins()
→ descriptor id org.openmbee.opensysml.mdk
→ Method docGen(BaseElement, String, String) ─► OpenSysMLPlugin.docGen
DocGenBridge: SelectionResolver → Engine.run
RunResult → Map<String,Object> (JDK types only)
BridgeResult.parse(map) ◄───────────────────────────┘
DocBookRenderer → DBParagraph / DBTable
Only Cameo OpenAPI types and JDK types (String, Map, List, Long) cross the boundary,
both of which are loaded once, by Cameo's shared classloader, so no ClassCastException can
arise. The target is typed com.nomagic.magicdraw.uml.BaseElement, the supertype of both the
UML Element and the KerML API Element, so a SysML v2 target takes the textual path through
the same SelectionResolver as the context menu (§7) and the bridge never loads a KerML class. The facade is a single public method on the Plugin instance,
found reflectively, so the bridge needs no compile-time dependency on the plugin and an older
plugin without the method fails with a readable message rather than a NoSuchMethodError.
Failure handling is per target: a target that is not a BaseElement, an operation the plugin
does not know, a service failure or a failed export each become one error paragraph; the rest
of the document still generates. A result whose temporary export could not be removed carries
an export-cleanup warning diagnostic, as the context-menu path does.
MDK resolves the extension class from the applied stereotype's name, so the model needs one
stereotype per operation, each specialising «JavaExtension». Shipping them as a profile
as a module would pin a profile .mdzip into the distribution; instead the plugin creates them
in the project on demand (OpenSysML ▸ Add MDK DocGen extension stereotypes on the model root):
a Profile named OpenSysML MDK DocGen under the primary model, applied to it with
StereotypesHelper.applyProfile so its stereotypes are applicable, with stereotypes
org.openmbee.opensysml.mdk.docgen.{Instantiate,ExecuteAction,ExecuteState,Verify,EvaluateCalc,RunAnalysis},
each extending Activity and CallBehaviorAction with a generalization to «JavaExtension»;
EvaluateCalc adds a String tag arguments. The action is idempotent and runs inside one
SessionManager session so it is a single undo step.
The bridge compiles against mdk-api-stubs, compile-only copies of the six MDK classes it
touches (Query, DocGenElement, Generatable, DocumentElement, DBParagraph, DBText,
DBTable), written from MDK's develop source because MDK publishes no API artifact. As with
the OpenAPI stubs (§10.3) only the members the bridge uses are declared, and they are never
shipped. The distribution assembly adds the bridge jar at
plugins/org.openmbee.mdk/extensions/ with no transitive dependencies — the bridge has none at
run time — and lists it in no plugin.xml, so Cameo without MDK never loads it.
Everything above the unit tests is reasoned from MDK's source and the vendor's Javadoc, not
run: no Cameo installation and no MDK installation were available. Specifically unverified are
that MDK's develop Query API is what the next MDK release ships; that
PluginUtils.getPlugins() returns the OpenSysML Plugin instance (rather than a proxy) so the
reflective call reaches docGen; that the UML String type is at
UML Standard Profile::UML2 Metamodel::PrimitiveTypes::String in 2026x (the installer leaves the
arguments tag untyped and says so if not); and the DocBook rendering of the tables in View
Editor as opposed to the PDF path.