Skip to content

ST6RI-178 Implement versioned publishing #633

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 213 commits into from
May 19, 2025
Merged

ST6RI-178 Implement versioned publishing #633

merged 213 commits into from
May 19, 2025

Conversation

TheKorpos
Copy link
Contributor

@TheKorpos TheKorpos commented Mar 10, 2025

This PR adds basic versioned publishing capabilities to Jupyter using the standard API.

Summary

Previously, the %publish command in Jupyter always created a new project on the API server, posting all elements of a model in the one and only commit on the "main" branch. The changes in this PR allow users to post incremental changes based to a specified project based on the delta between the remotely stored models and their local models. While currently this usually means that the new commit completely replaces the content of the model – since re-parsing a model in Jupyter creates entirely new element UUIDs – it is at least possible to publish multiple versions of a model in multiple commits to a single project in the repository.

Core Changes

  • org.omg.sysml.util.repository
    • Java APIs to provide common functionality for API server interactions (in org.omg.sysml.util.repository)
      • ProjectRepository: represents a standard API server
      • RemoteProject: represents a project that exists on the standard API server
      • RemoteBranch: represents a branch that exists in a project
      • Revision: represents a commit on a specific branch; can be local only (e.g., future initial commit)
      • APIModel: REST API-compatible representation of the model
      • APIModelDelta: differences between two APIModels
    • Logic to synch EMF models with APIModels
      • EMFModelRefresher: creates an EMFModelDelta from an EMF model and from an APIModel
      • EMFModelDelta: can be used to refresh the EMF model.
  • org.omg.sysml.util.traversal.facade.impl
    • Logic to create APIModels from EMF models
      • JsonElementProcessingFacade: updated so it can be configured to produce either an APIModel or an APIModelDelta (all additions)
      • ApiElementProcessingFacade: updated to use new Java APIs

Jupyter

Updated magic command:

%publish [-d] [--project=<PROJECT NAME>] [--branch=<BRANCH NAME>] <NAME>

Publish the model elements rooted in <NAME> to the repository. <NAME> must be fully qualified.
Use the -d flag to include derived properties.
If <PROJECT NAME> is given, it is used as the name of the project to create or update.
If <PROJECT NAME> is not given, the (simple) name of the model element is used.
    If no project exits with the given name, then a new project with that name is created.
    Otherwise, the existing project is updated with a new commit.
If <BRANCH NAME> is given, then the model is written to this branch of the project.
If <BRANCH NAME> is not given, the default branch is used.

seidewitz and others added 30 commits November 8, 2023 18:06
@TheKorpos
Copy link
Contributor Author

@seidewitz
I added the alphabetic ordering of listed repository projects.

Is lexicographic ordering good enough (Project11 coming before Project2) or should I use alphanumeric ordering? I couldn't find a good lib for alphanumeric sorting so probably I'd have to implement one.

@seidewitz
Copy link
Member

Is lexicographic ordering good enough (Project11 coming before Project2) or should I use alphanumeric ordering?

Lexicographic ordering is fine.

@seidewitz
Copy link
Member

The command

%load --branch=test --id="e8d6c606-728a-43ae-84a3-6fe8853e460f"

results in an exception:

java.lang.IllegalArgumentException: Invalid UUID string: test
	at java.base/java.util.UUID.fromString1(UUID.java:280)
	at java.base/java.util.UUID.fromString(UUID.java:258)
	at org.omg.sysml.interactive.SysMLInteractive.loadById(SysMLInteractive.java:471)
	at org.omg.sysml.jupyter.kernel.magic.Load.load(Load.java:56)
	at jdk.internal.reflect.GeneratedMethodAccessor8.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.github.spencerpark.jupyter.kernel.magic.registry.Magics.invoke(Magics.java:89)
	at io.github.spencerpark.jupyter.kernel.magic.registry.Magics.access$000(Magics.java:8)
	at io.github.spencerpark.jupyter.kernel.magic.registry.Magics$LineReflectionMagicFunction.execute(Magics.java:149)
	at io.github.spencerpark.jupyter.kernel.magic.registry.Magics.applyLineMagic(Magics.java:26)
	at org.omg.sysml.jupyter.kernel.SysMLKernel.eval(SysMLKernel.java:94)
	at io.github.spencerpark.jupyter.kernel.BaseKernel.handleExecuteRequest(BaseKernel.java:334)
	at io.github.spencerpark.jupyter.channels.ShellChannel.lambda$bind$0(ShellChannel.java:64)
	at io.github.spencerpark.jupyter.channels.Loop.lambda$new$0(Loop.java:21)
	at io.github.spencerpark.jupyter.channels.Loop.run(Loop.java:78)

This is true whether or not test is a valid branch (in this case it was). The branch option works fine if a project name is given.

@seidewitz
Copy link
Member

seidewitz commented May 15, 2025

If a name and ID are both given in a %load command, this results in the error message:

Name and id cannot be provided at the same time.

For consistency, this message should begin with "ERROR:".

@TheKorpos
Copy link
Contributor Author

%load --branch=test --id="e8d6c606-728a-43ae-84a3-6fe8853e460f"

Currenlty the load command is set up in a way that referencing a project by UUID also requires the branch to be referenced by UUID.

The question is do we want to refeference branches by UUID? If the answer is yes, we probably should add --branchId too. Otherwise --branch should be the name of the branch.

@seidewitz
Copy link
Member

seidewitz commented May 16, 2025

%load --branch=test --id="e8d6c606-728a-43ae-84a3-6fe8853e460f"

Currently the load command is set up in a way that referencing a project by UUID also requires the branch to be referenced by UUID.

I don't think this is intuitive. It certainly wasn't what I expected as a user. And it is not documented in the help

The question is do we want to refeerence branches by UUID? If the answer is yes, we probably should add --branchId too. Otherwise --branch should be the name of the branch.

I hadn't really considered using UUIDs to identify branches. But I supposed it is consistent to have that option, too. It does need to be a separate option, though.

Note that this will also require an update to the help text. But perhaps we should wait and to that on ST6RI-823 (PR #649), so we don't impact the work of @ujhelyiz on that.

@TheKorpos
Copy link
Contributor Author

@seidewitz
I've actually prepared an update, I haven't pushed yet, which makes load a little bit more flexible in the SysMLInteractive and allows all 4 cases.
I haven't made the --branchId option in Jupyter though (maybe --branch-id is a better name).

I hadn't really considered using UUIDs to identify branches. But I supposed it is consistent to have that option, too. It does need to be a separate option, though.

By not having it as a separate option you mean testing for UUID and going with name if it's not a valid UUID?

Note that this will also require an update to the help text. But perhaps we should wait and to that on ST6RI-823 (PR #649), so we don't impact the work of @ujhelyiz on that.

I agree. We should revisit the help text after @ujhelyiz's update is in.

Previously loading required using UUID or name to reference projects and
their branches but there were no interface that allowed mixing the two
e.g reference the project by UUID and the branch by name.

This rework makes load parameterization more flexible to allow more
cases to be covered.
@TheKorpos
Copy link
Contributor Author

@seidewitz
I pushed the update. --branch uses name now regardless of how the project was referenced. This is consistent with the current help text.

Allowing UUID for branches by either method can be easly done on top of this.

@TheKorpos
Copy link
Contributor Author

Name and id cannot be provided at the same time.

I've addressed this too.

@seidewitz
Copy link
Member

seidewitz commented May 16, 2025

Allowing UUID for branches by either method can be easily done on top of this.

What I meant previously was that --branch should always take the branch name, as you have now implemented. Go ahead and add a new option (--branchid is fine) that takes the branch ID. As for project, the name and ID options should be mutually exclusive.

Also, the use of name/ID for branch should be independent of the choice of name/ID for project.

TheKorpos and others added 2 commits May 16, 2025 19:57
- Also corrected the incrementing of "counter" in the %projects and
%load commands.
@seidewitz
Copy link
Member

I updated SysMLInteractive::run() to provide capabilities for the %projects and %load commands when the program is run within the Eclipse environment. I also added proper updating of counter for these commands.

@seidewitz
Copy link
Member

When a project is loaded, the %list command fails on the top-level element of the project, though it seems to work on lower-level elements. E.g.,

image

If this is run in the Eclipse environment, there is a more useful exception trace:

1> %load AnotherTest
Selected branch main
Caching library UUIDs...
Downloading model...
Loaded Project AnotherTest (0e5b9fb8-4bb8-4296-a37a-648c8444ba2f)
3> %list AnotherTest
1    [main] ERROR xt.linking.lazy.LazyLinkingResource  - resolution of uriFragment '|0' failed.
java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:223)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:209)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:269)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eResolveProxy(BasicEObjectImpl.java:1516)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getImportedMembership(MembershipImportImpl.java:74)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getTarget(MembershipImportImpl.java:121)
	at org.omg.sysml.lang.sysml.impl.RelationshipImpl.eGet(RelationshipImpl.java:325)
	at org.omg.sysml.lang.sysml.impl.ImportImpl.eGet(ImportImpl.java:446)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.eGet(MembershipImportImpl.java:149)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1050)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1042)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1037)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:175)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.listQuery(SysMLInteractive.java:337)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:351)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:357)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:765)
	at org.omg.sysml.interactive.SysMLInteractive.main(SysMLInteractive.java:842)
5    [main] ERROR xt.linking.lazy.LazyLinkingResource  - resolution of uriFragment '|0' failed.
java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:223)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:213)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:269)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eResolveProxy(BasicEObjectImpl.java:1516)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getImportedMembership(MembershipImportImpl.java:74)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getTarget(MembershipImportImpl.java:121)
	at org.omg.sysml.lang.sysml.impl.RelationshipImpl.eGet(RelationshipImpl.java:325)
	at org.omg.sysml.lang.sysml.impl.ImportImpl.eGet(ImportImpl.java:446)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.eGet(MembershipImportImpl.java:149)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1050)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1042)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1037)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:175)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.listQuery(SysMLInteractive.java:337)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:351)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:357)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:765)
	at org.omg.sysml.interactive.SysMLInteractive.main(SysMLInteractive.java:842)
6    [main] ERROR xt.linking.lazy.LazyLinkingResource  - resolution of uriFragment '|0' failed.
java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:183)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.listQuery(SysMLInteractive.java:337)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:351)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:357)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:765)
	at org.omg.sysml.interactive.SysMLInteractive.main(SysMLInteractive.java:842)
java.lang.NullPointerException: Cannot invoke "org.omg.sysml.lang.sysml.Namespace.getImportedMembership()" because the return value of "org.omg.sysml.interactive.SysMLInteractiveResult.getRootElement()" is null
	at org.omg.sysml.interactive.SysMLInteractive.listQuery(SysMLInteractive.java:341)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:351)
	at org.omg.sysml.interactive.SysMLInteractive.list(SysMLInteractive.java:357)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:765)
	at org.omg.sysml.interactive.SysMLInteractive.main(SysMLInteractive.java:842)
4>

- The "next" method should only be used to create a resource for a
model entered in a Jupyter notebook cell.
@seidewitz
Copy link
Member

The use of next here is a problem:

	private String load(RemoteBranch branch) {
		...
		delta.getProjectRoots().forEach((eObject, dto) -> {
			next(SYSMLX_EXTENSION);
			Resource xmiResource = getResource();
			if (eObject instanceof Namespace) {
				xmiResource.getContents().add(eObject);
			} else {
				Namespace root = SysMLFactory.eINSTANCE.createNamespace();
				NamespaceUtil.addOwnedMemberTo(root, (Element) eObject);
				xmiResource.getContents().add(root);
			}
			addResourceToIndex(xmiResource);
		});
		
		return "Loaded Project " + remoteProject.getProjectName() + " (" + remoteProject.getRemoteId().toString() + ")\n";
	}

The next method increments the counter, so it will get incremented for each root namespace loaded. But the intent is that the counter always reflect the corresponding Jupyter cell number, and the use of next hear will throw that out of sync, particularly if there are multiple root namespaces.

To fix this, I have replaced the lines

			next(SYSMLX_EXTENSION);
			Resource xmiResource = getResource();

with

			Resource resource = this.createResource(eObject.toString() + SYSML_EXTENSION);
			this.addInputResource(resource);

@seidewitz
Copy link
Member

The command %list AnotherTest is implemented by processing private import AnotherTest;. It is the import that is failing. Any import of the loaded top-level element fails:

11> %
package Test {
    public import AnotherTest;
}
%
2185596 [main] ERROR xt.linking.lazy.LazyLinkingResource  - resolution of uriFragment '|0' failed.
java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:223)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:209)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:269)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eResolveProxy(BasicEObjectImpl.java:1516)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getImportedMembership(MembershipImportImpl.java:74)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getTarget(MembershipImportImpl.java:121)
	at org.omg.sysml.lang.sysml.impl.RelationshipImpl.eGet(RelationshipImpl.java:325)
	at org.omg.sysml.lang.sysml.impl.ImportImpl.eGet(ImportImpl.java:446)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.eGet(MembershipImportImpl.java:149)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1050)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1042)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1037)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:175)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:239)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:732)
	at org.omg.sysml.interactive.SysMLInteractive.run(Unknown Source)
	at org.omg.sysml.interactive.SysMLInteractive.main(Unknown Source)
2185597 [main] ERROR xt.linking.lazy.LazyLinkingResource  - resolution of uriFragment '|0' failed.
java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:223)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:213)
	at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:269)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eResolveProxy(BasicEObjectImpl.java:1516)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getImportedMembership(MembershipImportImpl.java:74)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.getTarget(MembershipImportImpl.java:121)
	at org.omg.sysml.lang.sysml.impl.RelationshipImpl.eGet(RelationshipImpl.java:325)
	at org.omg.sysml.lang.sysml.impl.ImportImpl.eGet(ImportImpl.java:446)
	at org.omg.sysml.lang.sysml.impl.MembershipImportImpl.eGet(MembershipImportImpl.java:149)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1050)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1042)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eGet(BasicEObjectImpl.java:1037)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:175)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:239)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:732)
	at org.omg.sysml.interactive.SysMLInteractive.run(Unknown Source)
	at org.omg.sysml.interactive.SysMLInteractive.main(Unknown Source)
2185598 [main] ERROR xt.linking.lazy.LazyLinkingResource  - resolution of uriFragment '|0' failed.
java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:183)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:239)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:732)
	at org.omg.sysml.interactive.SysMLInteractive.run(Unknown Source)
	at org.omg.sysml.interactive.SysMLInteractive.main(Unknown Source)
org.eclipse.emf.common.util.WrappedException: java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:244)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:183)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:162)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:148)
	at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:505)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:162)
	at org.omg.kerml.xtext.validation.KerMLResourceValidator.resolveProxies(KerMLResourceValidator.java:42)
	at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
	at org.omg.sysml.interactive.SysMLInteractive.validate(SysMLInteractive.java:212)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:246)
	at org.omg.sysml.interactive.SysMLInteractive.process(SysMLInteractive.java:239)
	at org.omg.sysml.interactive.SysMLInteractive.run(SysMLInteractive.java:732)
	at org.omg.sysml.interactive.SysMLInteractive.run(Unknown Source)
	at org.omg.sysml.interactive.SysMLInteractive.main(Unknown Source)
Caused by: java.lang.NullPointerException: Cannot invoke "org.eclipse.emf.ecore.EObject.eClass()" because "result" is null
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:280)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:236)
	... 13 more
12> 

@TheKorpos
Copy link
Contributor Author

@seidewitz
Thank you for the updates.

When a project is loaded, the %list command fails on the top-level element of the project, though it seems to work on lower-level elements. E.g.,

The problem here is that when you publish a namespace from Jupyter the root Namespace and the OwningMembership is not uploaded as they're out of scope. So the membership import can't reference the OwningMembership.

These lines of code, that you've since adjusted, meant to account for this:

  delta.getProjectRoots().forEach((eObject, dto) -> {
  	next(SYSMLX_EXTENSION);
  	Resource xmiResource = getResource();
  	if (eObject instanceof Namespace) {
  		xmiResource.getContents().add(eObject);
  	} else {
  		Namespace root = SysMLFactory.eINSTANCE.createNamespace();
  		NamespaceUtil.addOwnedMemberTo(root, (Element) eObject);
  		xmiResource.getContents().add(root);
  	}
  	addResourceToIndex(xmiResource);
  });

This should wrap non-namepsace roots in a Namespace with an OwningMembership, but I made a mistake. Instead of eObject instanceof Namespace it should be eObject.eClass() == SysMLPackage.eINSTANCE.getNamespace().

This is only done in the Jupyter %load command. However Eclipse and the CLI utility should also wrap project roots under a rootnamespace.

Alternatively, we could modify the %publish command, so that it uploads the whole ownership hierarchy leading to the selected Namespace. That would eliminate the need of ceating this wrapper Namespace. However the API doesn't require the model to be rooted in Namepsaces (at least I couldn't find such constraint) so I think it's the loading that should account for these kind of models.

@seidewitz
Copy link
Member

@TheKorpos
I was replying to your previous comment when I say your new commit. Does this change also cover the Eclipse and CLI utility, in addition to %load?

@TheKorpos
Copy link
Contributor Author

I was replying to your previous comment when I say your new commit. Does this change also cover the Eclipse and CLI utility, in addition to %load?

Yes. I made the Namespace wrapping a core part of the logic. All versions of load use it now.

@seidewitz seidewitz merged commit 6994d25 into ST6RI-682 May 19, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants