diff --git a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerML2JSON.java b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerML2JSON.java
index 278e137bf..6d60431ff 100644
--- a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerML2JSON.java
+++ b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerML2JSON.java
@@ -165,24 +165,23 @@ public void run(String[] args) {
args = this.processArgs(args);
if (args != null) {
-
- System.out.println("Saving " + args[0] + "...");
-
- this.initialize(args);
- this.read(args);
-
- System.out.println("Transforming" +
- (this.isAddImplicitElements? " (adding implicit elements)... ": "..."));
- this.transformAll(this.isAddImplicitElements);
-
- if (!this.isVerbose()) {
- System.out.print("Processing");
- }
- this.process();
- System.out.println();
-
- System.out.println("Writing " + this.outputPath + "...");
try {
+ System.out.println("Saving " + args[0] + "...");
+
+ this.initialize(args);
+ this.read(args);
+
+ System.out.println("Transforming" +
+ (this.isAddImplicitElements? " (adding implicit elements)... ": "..."));
+ this.transformAll(this.isAddImplicitElements);
+
+ if (!this.isVerbose()) {
+ System.out.print("Processing");
+ }
+ this.process();
+ System.out.println();
+
+ System.out.println("Writing " + this.outputPath + "...");
this.write();
} catch (IOException e) {
throw new RuntimeException(e);
diff --git a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerMLRepositorySaveUtil.java b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerMLRepositorySaveUtil.java
index 9e11c7266..38415bd1d 100644
--- a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerMLRepositorySaveUtil.java
+++ b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/util/KerMLRepositorySaveUtil.java
@@ -25,6 +25,7 @@
*****************************************************************************/
package org.omg.kerml.xtext.util;
+import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -237,26 +238,30 @@ public void run(String[] args) {
args = this.processArgs(args);
if (args != null) {
- System.out.println("Saving " + args[0] + "...");
-
- this.initialize(args);
- this.read(args);
-
- System.out.println("Transforming" +
- (this.isAddImplicitElements? " (adding implicit generalizations)... ": "..."));
- this.transformAll(this.isAddImplicitElements);
-
- System.out.println("\nBase path is " + this.getBasePath());
- System.out.println();
-
- this.process();
-
- if (isCommitted()) {
- System.out.println("Saved to Project (" + this.getProjectName() + ") " + this.getProjectId());
- } else {
- System.out.println("Failed to save Project (" + this.getProjectName() + ") ");
+ try {
+ System.out.println("Saving " + args[0] + "...");
+
+ this.initialize(args);
+ this.read(args);
+
+ System.out.println("Transforming" +
+ (this.isAddImplicitElements? " (adding implicit generalizations)... ": "..."));
+ this.transformAll(this.isAddImplicitElements);
+
+ System.out.println("\nBase path is " + this.getBasePath());
+ System.out.println();
+
+ this.process();
+
+ if (isCommitted()) {
+ System.out.println("Saved to Project (" + this.getProjectName() + ") " + this.getProjectId());
+ } else {
+ System.out.println("Failed to save Project (" + this.getProjectName() + ") ");
+ }
+ System.out.println();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
- System.out.println();
}
}
diff --git a/org.omg.sysml.interactive.tests/.launch/SysML Access Test.launch b/org.omg.sysml.interactive.tests/.launch/SysML Access Test.launch
new file mode 100644
index 000000000..c5e18a0a2
--- /dev/null
+++ b/org.omg.sysml.interactive.tests/.launch/SysML Access Test.launch
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.omg.sysml.interactive.tests/META-INF/MANIFEST.MF b/org.omg.sysml.interactive.tests/META-INF/MANIFEST.MF
index e48ab309c..d33b705d1 100644
--- a/org.omg.sysml.interactive.tests/META-INF/MANIFEST.MF
+++ b/org.omg.sysml.interactive.tests/META-INF/MANIFEST.MF
@@ -9,4 +9,5 @@ Bundle-ActivationPolicy: lazy
Require-Bundle: org.omg.sysml.interactive;bundle-version="0.3.2",
org.junit;bundle-version="4.12.0",
org.omg.sysml,
- org.eclipse.xtext;bundle-version="2.22.0"
+ org.eclipse.xtext;bundle-version="2.22.0",
+ org.omg.sysml.xtext
diff --git a/org.omg.sysml.interactive.tests/resources/org/omg/sysml/parseTest.sysml b/org.omg.sysml.interactive.tests/resources/org/omg/sysml/parseTest.sysml
new file mode 100644
index 000000000..a96ffb10a
--- /dev/null
+++ b/org.omg.sysml.interactive.tests/resources/org/omg/sysml/parseTest.sysml
@@ -0,0 +1,5 @@
+package P {
+ part def a {
+ part b;
+ }
+}
\ No newline at end of file
diff --git a/org.omg.sysml.interactive.tests/resources/org/omg/sysml/parseTestWithError.sysml b/org.omg.sysml.interactive.tests/resources/org/omg/sysml/parseTestWithError.sysml
new file mode 100644
index 000000000..18d034947
--- /dev/null
+++ b/org.omg.sysml.interactive.tests/resources/org/omg/sysml/parseTestWithError.sysml
@@ -0,0 +1,4 @@
+package P {
+ part def a {
+ part b;
+ }
diff --git a/org.omg.sysml.interactive.tests/src/org/omg/sysml/SysMLAccessTest.java b/org.omg.sysml.interactive.tests/src/org/omg/sysml/SysMLAccessTest.java
new file mode 100644
index 000000000..c6e1d475d
--- /dev/null
+++ b/org.omg.sysml.interactive.tests/src/org/omg/sysml/SysMLAccessTest.java
@@ -0,0 +1,94 @@
+package org.omg.sysml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.junit.Test;
+import org.omg.sysml.lang.sysml.Element;
+import org.omg.sysml.xtext.util.SysMLAccess;
+import org.omg.sysml.xtext.util.SysMLParseResult;
+
+public class SysMLAccessTest {
+
+ private final static String SYSML_LIBRARY_PATH_KEY = "libraryPath";
+
+ public String getLibraryPath() {
+ return System.getProperty(SYSML_LIBRARY_PATH_KEY);
+ }
+
+ @Test
+ public void testReadLibrary() throws IOException {
+ SysMLAccess sysmlAccess = SysMLAccess.createFullyFeatured(getLibraryPath());
+ sysmlAccess.setVerbose(false);
+ sysmlAccess.loadLibrary();
+ Set libraryResources = sysmlAccess.getLibraryResources();
+ assertTrue("Libray was not loaded", !libraryResources.isEmpty());
+ }
+
+ @Test
+ public void testResolution() throws IOException {
+ SysMLAccess sysmlAccess = SysMLAccess.createFullyFeatured(getLibraryPath());
+ sysmlAccess.setVerbose(false);
+ sysmlAccess.loadLibrary();
+
+ Element element = sysmlAccess.resolve("$::Parts::parts");
+ assertNotNull(element);
+ assertEquals("Parts::parts", element.getQualifiedName());
+ }
+
+ @Test
+ public void testParsing() throws IOException {
+ SysMLAccess sysmlAccess = SysMLAccess.createFullyFeatured(getLibraryPath());
+ sysmlAccess.setVerbose(false);
+ sysmlAccess.loadLibrary();
+
+ SysMLParseResult result = sysmlAccess.parse("myres.sysml", "package P { part b; }");
+ assertTrue(result.getIssues().isEmpty());
+ }
+
+ @Test
+ public void testParsingWithError() throws IOException {
+ SysMLAccess sysmlAccess = SysMLAccess.createFullyFeatured(getLibraryPath());
+ sysmlAccess.setVerbose(false);
+ sysmlAccess.loadLibrary();
+
+ SysMLParseResult result = sysmlAccess.parse("myres.sysml", "package P { part b; ");
+ assertFalse(result.getSyntaxErrors().isEmpty());
+ }
+
+ @Test
+ public void testParseFile() throws IOException, URISyntaxException {
+ SysMLAccess sysmlAccess = SysMLAccess.createFullyFeatured(getLibraryPath());
+ sysmlAccess.setVerbose(false);
+ sysmlAccess.loadLibrary();
+
+ URL testFileURL = getClass().getResource("parseTest.sysml");
+ File testFile = new File(testFileURL.toURI());
+ List results = sysmlAccess.parseFiles(testFile, true);
+
+ assertTrue(results.getFirst().getSyntaxErrors().isEmpty());
+ }
+
+ @Test
+ public void testParseFileWithError() throws IOException, URISyntaxException {
+ SysMLAccess sysmlAccess = SysMLAccess.createFullyFeatured(getLibraryPath());
+ sysmlAccess.setVerbose(false);
+ sysmlAccess.loadLibrary();
+
+ URL testFileURL = getClass().getResource("parseTestWithError.sysml");
+ File testFile = new File(testFileURL.toURI());
+ List results = sysmlAccess.parseFiles(testFile, true);
+
+ assertFalse(results.getFirst().getSyntaxErrors().isEmpty());
+ }
+}
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractive.java b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractive.java
index 4bd8fbd77..b4d9d1898 100644
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractive.java
+++ b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractive.java
@@ -40,25 +40,17 @@
import java.util.stream.Collectors;
import org.eclipse.emf.common.util.BasicEList;
-import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
-import org.eclipse.xtext.parser.IParseResult;
-import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.XtextResource;
-import org.eclipse.xtext.scoping.IGlobalScopeProvider;
-import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.validation.CheckMode;
-import org.eclipse.xtext.validation.IResourceValidator;
import org.eclipse.xtext.validation.Issue;
import org.omg.kerml.xtext.KerMLStandaloneSetup;
import org.omg.kerml.xtext.xmi.KerMLxStandaloneSetup;
-import org.omg.kerml.xtext.library.ILibraryIndexProvider;
-import org.omg.kerml.xtext.naming.KerMLQualifiedNameConverter;
import org.omg.sysml.execution.expressions.ExpressionEvaluator;
import org.omg.sysml.lang.sysml.Element;
import org.omg.sysml.lang.sysml.Expression;
@@ -66,35 +58,34 @@
import org.omg.sysml.lang.sysml.Namespace;
import org.omg.sysml.lang.sysml.RenderingUsage;
import org.omg.sysml.lang.sysml.ResultExpressionMembership;
-import org.omg.sysml.lang.sysml.SysMLFactory;
import org.omg.sysml.lang.sysml.SysMLPackage;
import org.omg.sysml.lang.sysml.Type;
import org.omg.sysml.lang.sysml.ViewUsage;
-import org.omg.sysml.lang.sysml.util.SysMLLibraryUtil;
import org.omg.sysml.plantuml.SysML2PlantUMLLinkProvider;
import org.omg.sysml.plantuml.SysML2PlantUMLSvc;
import org.omg.sysml.util.SysMLUtil;
import org.omg.sysml.util.TypeUtil;
-import org.omg.sysml.util.repository.EObjectUUIDTracker;
import org.omg.sysml.util.repository.APIModel;
import org.omg.sysml.util.repository.EMFModelDelta;
+import org.omg.sysml.util.repository.EMFModelRefresher;
+import org.omg.sysml.util.repository.EObjectUUIDTracker;
import org.omg.sysml.util.repository.ProjectRepository;
-import org.omg.sysml.util.repository.Revision;
import org.omg.sysml.util.repository.RemoteProject;
import org.omg.sysml.util.repository.RemoteProject.RemoteBranch;
-import org.omg.sysml.util.repository.EMFModelRefresher;
+import org.omg.sysml.util.repository.Revision;
import org.omg.sysml.util.traversal.Traversal;
import org.omg.sysml.util.traversal.facade.impl.ApiElementProcessingFacade;
import org.omg.sysml.util.traversal.facade.impl.JsonElementProcessingFacade;
-import org.omg.sysml.xtext.xmi.SysMLxStandaloneSetup;
import org.omg.sysml.xtext.SysMLStandaloneSetup;
+import org.omg.sysml.xtext.util.StrictShadowingResourceDescriptionData;
+import org.omg.sysml.xtext.util.SysMLAccess;
+import org.omg.sysml.xtext.xmi.SysMLxStandaloneSetup;
-import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.Injector;
-public class SysMLInteractive extends SysMLUtil {
+public class SysMLInteractive extends SysMLAccess {
public static final String HELP_KEY = "help";
public static final String PROJECT_ID_KEY = "id";
@@ -102,15 +93,6 @@ public class SysMLInteractive extends SysMLUtil {
public static final String BRANCH_ID_KEY = "branch-id";
public static final String BRANCH_NAME_KEY = "branch";
- public static final String KERNEL_LIBRARIES_DIRECTORY = "Kernel Libraries";
- public static final String SYSTEMS_LIBRARY_DIRECTORY = "Systems Library";
- public static final String DOMAIN_LIBRARIES_DIRECTORY = "Domain Libraries";
-
- public static final String KERML_EXTENSION = ".kerml";
- public static final String SYSML_EXTENSION = ".sysml";
- public static final String KERMLX_EXTENSION = ".kermlx";
- public static final String SYSMLX_EXTENSION = ".sysmlx";
-
protected static Injector injector;
protected static SysMLInteractive instance = null;
@@ -123,39 +105,13 @@ public class SysMLInteractive extends SysMLUtil {
protected SysML2PlantUMLSvc sysml2PlantUMLSvc;
- private Resource dummyResource;
-
- @Inject
- private IGlobalScopeProvider scopeProvider;
-
- @Inject
- private KerMLQualifiedNameConverter qualifiedNameConverter;
-
- @Inject
- private IResourceValidator validator;
-
- @Inject
- private ILibraryIndexProvider libraryIndexCache;
-
private EObjectUUIDTracker tracker = new EObjectUUIDTracker();
@Inject
private SysMLInteractive() {
super(new StrictShadowingResourceDescriptionData());
}
-
- public void loadLibrary(String path) {
- if (path != null) {
- if (!path.endsWith("/")) {
- path += "/";
- }
- SysMLLibraryUtil.setModelLibraryDirectory(path);
- this.readAll(path + KERNEL_LIBRARIES_DIRECTORY, false, KERML_EXTENSION);
- this.readAll(path + SYSTEMS_LIBRARY_DIRECTORY, false, SYSML_EXTENSION);
- this.readAll(path + DOMAIN_LIBRARIES_DIRECTORY, false, SYSML_EXTENSION);
- }
- }
-
+
public void setApiBasePath(String apiBasePath) {
this.apiBasePath = apiBasePath;
}
@@ -174,10 +130,6 @@ public Resource getResource() {
return this.resource;
}
- public ILibraryIndexProvider getLibraryIndexCache() {
- return libraryIndexCache;
- }
-
public void removeResource() {
if (this.resource != null) {
try {
@@ -191,13 +143,7 @@ public void removeResource() {
public Element getRootElement() {
Resource resource = this.getResource();
- if (resource instanceof XtextResource xtextResource) {
- final IParseResult result = xtextResource.getParseResult();
- return result == null? null: (Element)result.getRootASTElement();
- } else {
- EList contents = resource.getContents();
- return contents.isEmpty()? null: (Element)contents.get(0);
- }
+ return getRootElement(resource);
}
public void parse(String input) throws IOException {
@@ -215,29 +161,6 @@ public List validate() {
validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl);
}
- private Resource getDummyResource() {
- if (this.dummyResource == null) {
- this.dummyResource = this.createResource("dummy" + SYSML_EXTENSION);
- this.dummyResource.getContents().add(SysMLFactory.eINSTANCE.createNamespace());
- }
- return this.dummyResource;
- }
-
- public Element resolve(String name) {
- IScope scope = scopeProvider.getScope(
- this.getDummyResource(),
- SysMLPackage.eINSTANCE.getNamespace_Member(),
- Predicates.alwaysTrue());
- IEObjectDescription description = scope.getSingleElement(
- this.qualifiedNameConverter.toQualifiedName(name));
- if (description == null) {
- return null;
- } else {
- EObject object = description.getEObjectOrProxy();
- return object instanceof Element? (Element)object: null;
- }
- }
-
public SysMLInteractiveResult process(String input) {
return process(input, true);
}
@@ -279,6 +202,15 @@ public String help(String command) {
help(command, Collections.emptyList());
}
+ public void loadLibrary(String path) {
+ try {
+ setModelLibraryDirectory(path);
+ loadLibrary();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
public String repo(String apiBasePath, List help) {
this.counter++;
if (!help.isEmpty()) {
@@ -327,7 +259,7 @@ public String eval(String input, String targetName, List help) {
List elements = ExpressionEvaluator.INSTANCE.evaluate(expr, target);
this.removeResource();
return elements == null? "":
- elements.stream().map(SysMLInteractiveUtil::formatElement).collect(Collectors.joining());
+ elements.stream().map(SysMLUtil::formatElement).collect(Collectors.joining());
}
}
@@ -346,9 +278,9 @@ public String listLibrary() {
filter(Namespace.class::isInstance).
flatMap(n->((Namespace)n).visibleMemberships(new BasicEList<>(), false, false).stream()).
collect(Collectors.toList());
- return SysMLInteractiveUtil.formatMembershipList(globalMemberships);
+ return SysMLUtil.formatMembershipList(globalMemberships);
} catch (Exception e) {
- return SysMLInteractiveUtil.formatException(e);
+ return SysMLUtil.formatException(e);
}
}
@@ -362,7 +294,7 @@ public String listQuery(String query) {
} else {
List memberships = ((Namespace)result.getRootElement()).getImportedMembership();
this.removeResource();
- return SysMLInteractiveUtil.formatMembershipList(memberships);
+ return SysMLUtil.formatMembershipList(memberships);
}
}
@@ -395,12 +327,12 @@ else if (matchStyle(styles, "JSON")) {
return processingFacade.toJsonTree(true);
}
else if (styles.isEmpty() || matchStyle(styles, "TREE")){
- return SysMLInteractiveUtil.formatTree(element);
+ return SysMLUtil.formatTree(element);
} else {
return "ERROR:Invalid style. Possible styles: TREE and JSON\n";
}
} catch (Exception e) {
- return SysMLInteractiveUtil.formatException(e);
+ return SysMLUtil.formatException(e);
}
}
@@ -418,7 +350,7 @@ public Object export(String name, List help) {
processingFacade.getTraversal().visit(element);
return processingFacade.toJsonTree(true);
} catch (Exception e) {
- return SysMLInteractiveUtil.formatException(e);
+ return SysMLUtil.formatException(e);
}
}
@@ -457,7 +389,7 @@ public String publish(String elementName, String projectName, String branchName,
return "Saved to Project " + remoteProjectName + " (" + processingFacade.getProjectId() + ")\n";
}
} catch (Exception e) {
- return SysMLInteractiveUtil.formatException(e);
+ return SysMLUtil.formatException(e);
}
}
@@ -854,7 +786,7 @@ public static SysMLInteractive getInstance() {
return instance;
}
- public static void main(String[] args) {
+ public static void main(String[] args) throws IOException {
System.out.println("SysML v2 Pilot Implementation");
SysMLInteractive instance = getInstance();
if (args.length > 0) {
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveLibraryIndexGenerator.java b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveLibraryIndexGenerator.java
index 98b623cb8..bd26f022d 100644
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveLibraryIndexGenerator.java
+++ b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveLibraryIndexGenerator.java
@@ -31,6 +31,7 @@
import org.eclipse.xtext.EcoreUtil2;
import org.omg.kerml.xtext.library.LibraryIndex;
import org.omg.sysml.util.ElementUtil;
+import org.omg.sysml.xtext.util.SysMLAccess;
import com.google.gson.GsonBuilder;
@@ -52,10 +53,10 @@ public static void main(String[] args) throws IOException {
//disable EMF reference clearing to prevent InterruptedException on early JVM shutdown
System.setProperty("org.eclipse.emf.common.util.ReferenceClearingQueue", "false");
- SysMLInteractive instance = SysMLInteractive.getInstance();
- instance.getLibraryIndexCache().setIndexDisabled(true);
- instance.loadLibrary(args[0]);
+ SysMLAccess instance = SysMLAccess.builder().libraryPath(args[0]).build();
+ instance.getLibraryIndexCache().setIndexDisabled(true);
+ instance.loadLibrary();
ResourceSet rs = instance.getResourceSet();
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveResult.java b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveResult.java
index 424e0a510..0e4860d02 100644
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveResult.java
+++ b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveResult.java
@@ -31,6 +31,7 @@
import org.eclipse.xtext.validation.Issue;
import org.omg.sysml.lang.sysml.Element;
import org.omg.sysml.lang.sysml.Namespace;
+import org.omg.sysml.util.SysMLUtil;
public class SysMLInteractiveResult {
@@ -87,18 +88,18 @@ public String formatRootElement() {
Element rootElement = this.getRootElement();
return rootElement == null? "":
!(rootElement instanceof Namespace) || rootElement.getOwner() != null?
- SysMLInteractiveUtil.formatElement(rootElement):
+ SysMLUtil.formatElement(rootElement):
((Namespace)rootElement).getOwnedMember().stream().
- map(SysMLInteractiveUtil::formatElement).
+ map(SysMLUtil::formatElement).
collect(Collectors.joining());
}
public String formatIssues() {
- return SysMLInteractiveUtil.formatList(this.issues);
+ return SysMLUtil.formatList(this.issues);
}
public String formatException() {
- return SysMLInteractiveUtil.formatException(this.exception);
+ return SysMLUtil.formatException(this.exception);
}
@Override
@@ -108,11 +109,11 @@ public String toString() {
} else {
List syntaxErrors = this.getSyntaxErrors();
if (!syntaxErrors.isEmpty()) {
- return SysMLInteractiveUtil.formatList(syntaxErrors);
+ return SysMLUtil.formatList(syntaxErrors);
} else {
List semanticErrors = this.getSemanticErrors();
List warnings = this.getWarnings();
- String msgs = SysMLInteractiveUtil.formatList(semanticErrors) + SysMLInteractiveUtil.formatList(warnings);
+ String msgs = SysMLUtil.formatList(semanticErrors) + SysMLUtil.formatList(warnings);
return semanticErrors.isEmpty()? msgs + this.formatRootElement(): msgs;
}
}
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveUtil.java b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveUtil.java
deleted file mode 100644
index 08412c9c8..000000000
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/SysMLInteractiveUtil.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package org.omg.sysml.interactive;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.omg.sysml.lang.sysml.Element;
-import org.omg.sysml.lang.sysml.Expression;
-import org.omg.sysml.lang.sysml.Feature;
-import org.omg.sysml.lang.sysml.FeatureReferenceExpression;
-import org.omg.sysml.lang.sysml.InvocationExpression;
-import org.omg.sysml.lang.sysml.LiteralBoolean;
-import org.omg.sysml.lang.sysml.LiteralInfinity;
-import org.omg.sysml.lang.sysml.LiteralInteger;
-import org.omg.sysml.lang.sysml.LiteralRational;
-import org.omg.sysml.lang.sysml.LiteralString;
-import org.eclipse.emf.ecore.EClass;
-import org.omg.sysml.expressions.util.EvaluationUtil;
-import org.omg.sysml.lang.sysml.CalculationUsage;
-import org.omg.sysml.lang.sysml.Membership;
-import org.omg.sysml.lang.sysml.MetadataFeature;
-import org.omg.sysml.lang.sysml.OperatorExpression;
-import org.omg.sysml.lang.sysml.OwningMembership;
-import org.omg.sysml.lang.sysml.Relationship;
-import org.omg.sysml.lang.sysml.Type;
-import org.omg.sysml.util.TypeUtil;
-
-public class SysMLInteractiveUtil {
-
- public static final String INDENT = " ";
-
- private static String formatRelationship(EClass kind, String shortName, String memberName) {
- return "[" + kind.getName() +
- (shortName == null? "": " <" + shortName + ">") +
- (memberName == null? "": " " + memberName) +
- "] ";
- }
-
- private static String formatRelationship(Relationship relationship) {
- return relationship == null? "":
- relationship instanceof Membership && !(relationship instanceof OwningMembership)?
- formatRelationship(relationship.eClass(),
- ((Membership)relationship).getMemberShortName(),
- ((Membership)relationship).getMemberName()):
- formatRelationship(relationship.eClass(), null, null);
- }
-
- private static void formatElement(StringBuilder buffer, String indentation, Element element, String relationshipTag) {
- buffer.append(indentation + relationshipTag + element.eClass().getName());
- if (EvaluationUtil.isMetaclassFeature(element)) {
- formatElement(buffer, " ", ((MetadataFeature)element).getAnnotatedElement().get(0), "");
- } else {
- String shortName = element.getDeclaredShortName();
- String name = nameOf(element);
- buffer.append(
- (shortName == null? "": " <" + shortName + ">") +
- (name == null? "": " " + name) +
- " (" + element.getElementId() + ")\n");
- }
- }
-
- public static String nameOf(Element element) {
- if (element == null) {
- return "";
- } else if (element instanceof Feature && !((Feature)element).getOwnedFeatureChaining().isEmpty()) {
- String name = "";
- for (Feature chainingFeature: ((Feature)element).getChainingFeature()) {
- String nextName = chainingFeature.getName();
- if (nextName == null) {
- nextName = "";
- }
- if (name == "") {
- name = nextName;
- } else {
- name += "." + nextName;
- }
- }
- return name;
- } else {
- return element instanceof LiteralBoolean? Boolean.valueOf(((LiteralBoolean)element).isValue()).toString():
- element instanceof LiteralString? ((LiteralString)element).getValue().toString():
- element instanceof LiteralInteger? Integer.valueOf(((LiteralInteger)element).getValue()).toString():
- element instanceof LiteralRational? Double.valueOf(((LiteralRational)element).getValue()).toString():
- element instanceof LiteralInfinity? "*":
- element instanceof FeatureReferenceExpression? nameOf(((FeatureReferenceExpression)element).getReferent()):
- element instanceof OperatorExpression? ((OperatorExpression)element).getOperator():
- element instanceof InvocationExpression? nameOf(((InvocationExpression)element).getFunction()):
- element.getName();
- }
- }
-
- private static void formatExplicitElement(StringBuilder buffer, String indentation, Element element, Relationship relationship) {
- formatElement(buffer, indentation, element, formatRelationship(relationship));
- }
-
- private static void formatImplicitElement(StringBuilder buffer, String indentation, Element element, EClass kind) {
- formatElement(buffer, indentation, element, formatRelationship(kind, null, "(implicit)"));
- }
-
- private static void formatTree(StringBuilder buffer, String indentation, Element element, Relationship relationship) {
- formatExplicitElement(buffer, indentation, element, relationship);
- if (element instanceof Expression && !(element instanceof CalculationUsage)) {
- for (Element output: ((Expression)element).getOutput()) {
- if (output.getOwner() == element) {
- formatExplicitElement(buffer, indentation + SysMLInteractiveUtil.INDENT, output, output.getOwningMembership());
- }
- }
- } else {
- if (element instanceof Type) {
- TypeUtil.forEachImplicitGeneralTypeOf((Type)element, (kind, supertype)->
- formatImplicitElement(buffer, indentation + SysMLInteractiveUtil.INDENT, supertype, kind)
- );
- }
-
- for (Relationship subrelationship: element.getOwnedRelationship()) {
- for (Element relatedElement: subrelationship.getRelatedElement()) {
- if (relatedElement != element) {
- if (relatedElement.getOwningRelationship() == subrelationship) {
- formatTree(buffer, indentation + SysMLInteractiveUtil.INDENT, relatedElement, subrelationship);
- } else {
- formatExplicitElement(buffer, indentation + SysMLInteractiveUtil.INDENT, relatedElement, subrelationship);
- }
- }
- }
- }
- }
- }
-
- public static String formatElement(Element element) {
- StringBuilder buffer = new StringBuilder();
- formatExplicitElement(buffer, "", element, null);
- return buffer.toString();
- }
-
- public static String formatTree(Element element) {
- StringBuilder buffer = new StringBuilder();
- formatTree(buffer, "", element, null);
- return buffer.toString();
- }
-
- public static String formatList(List list) {
- StringBuilder buffer = new StringBuilder();
- list.stream().map(x->x.toString() + "\n").forEachOrdered(buffer::append);
- return buffer.toString();
- }
-
- public static String formatException(Exception exception) {
- StringWriter writer = new StringWriter();
- exception.printStackTrace(new PrintWriter(writer));
- return writer.toString();
- }
-
- public static String formatMembershipList(List membership) {
- return membership.stream().
- map(Membership::getMemberElement).
- sorted(SysMLInteractiveUtil::compare).
- map(SysMLInteractiveUtil::formatElement).
- collect(Collectors.joining());
- }
-
- public static int compare(Element element1, Element element2) {
- String humanId1 = element1.getDeclaredShortName();
- String humanId2 = element2.getDeclaredShortName();
- String name1 = element1.getName();
- String name2 = element2.getName();
- return name1 != null && name2 != null? name1.compareToIgnoreCase(name2):
- name1 == null && name2 != null? -1:
- name1 != null && name2 == null? 1:
- humanId1 != null && humanId2 != null? humanId1.compareToIgnoreCase(humanId2):
- humanId1 == null && humanId2 != null? -1:
- humanId1 != null && humanId2 == null? 1:
- 0;
- }
-
-}
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/VizResult.java b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/VizResult.java
index f503d1788..27281a1ba 100644
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/VizResult.java
+++ b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/VizResult.java
@@ -25,6 +25,8 @@
*****************************************************************************/
package org.omg.sysml.interactive;
+import org.omg.sysml.util.SysMLUtil;
+
public class VizResult {
public static enum Kind {
EXCEPTION,
@@ -62,7 +64,7 @@ public String formatException() {
return this.exception == null? "":
this.exception instanceof VizException? this.exception.getMessage():
this.exception instanceof IllegalArgumentException? "ERROR:" + this.exception.getMessage():
- SysMLInteractiveUtil.formatException(exception);
+ SysMLUtil.formatException(exception);
}
public String getPlantUML() {
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/profiler/SysMLInteractiveParsingProfiler.java b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/profiler/SysMLInteractiveParsingProfiler.java
index ccfe29c10..718dcb7a9 100644
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/profiler/SysMLInteractiveParsingProfiler.java
+++ b/org.omg.sysml.interactive/src/org/omg/sysml/interactive/profiler/SysMLInteractiveParsingProfiler.java
@@ -46,7 +46,8 @@ public static void main(String[] args) throws Exception {
System.out.println("Usage: ");
System.out.println("SysMLInteractiveParsingProfiler ");
}
- instance.loadLibrary(args[0]);
+ instance.setModelLibraryDirectory(args[0]);
+ instance.loadLibrary();
initWatch.stop();
System.out.println("Libraries loaded in " + initWatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
diff --git a/org.omg.sysml.jupyter.kernel/pom.xml b/org.omg.sysml.jupyter.kernel/pom.xml
index 449ce1e81..6bd026e68 100644
--- a/org.omg.sysml.jupyter.kernel/pom.xml
+++ b/org.omg.sysml.jupyter.kernel/pom.xml
@@ -22,6 +22,18 @@
*
+
+
+ org.omg.sysml
+ org.omg.sysml.xtext
+ ${project.version}
+
+
+
+ *
+ *
+
+
io.github.spencerpark
diff --git a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/StrictShadowingResourceDescriptionData.java b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/StrictShadowingResourceDescriptionData.java
similarity index 99%
rename from org.omg.sysml.interactive/src/org/omg/sysml/interactive/StrictShadowingResourceDescriptionData.java
rename to org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/StrictShadowingResourceDescriptionData.java
index ffd225bed..cb4ffda47 100644
--- a/org.omg.sysml.interactive/src/org/omg/sysml/interactive/StrictShadowingResourceDescriptionData.java
+++ b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/StrictShadowingResourceDescriptionData.java
@@ -22,7 +22,7 @@
* Ed Seidewitz
*
*****************************************************************************/
-package org.omg.sysml.interactive;
+package org.omg.sysml.xtext.util;
import java.util.Collections;
import java.util.LinkedHashMap;
diff --git a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLAPIAccess.java b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLAPIAccess.java
new file mode 100644
index 000000000..ed4f4425c
--- /dev/null
+++ b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLAPIAccess.java
@@ -0,0 +1,254 @@
+package org.omg.sysml.xtext.util;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.omg.sysml.lang.sysml.Element;
+import org.omg.sysml.util.repository.APIModel;
+import org.omg.sysml.util.repository.EMFModelDelta;
+import org.omg.sysml.util.repository.EMFModelRefresher;
+import org.omg.sysml.util.repository.EObjectUUIDTracker;
+import org.omg.sysml.util.repository.ProjectRepository;
+import org.omg.sysml.util.repository.RemoteProject;
+import org.omg.sysml.util.repository.Revision;
+import org.omg.sysml.util.repository.RemoteProject.RemoteBranch;
+import org.omg.sysml.util.traversal.Traversal;
+import org.omg.sysml.util.traversal.facade.impl.ApiElementProcessingFacade;
+import org.omg.sysml.util.traversal.facade.impl.JsonElementProcessingFacade;
+
+/**
+ * This API is used to publish or load models from the standard
+ * SysML REST and for JSON serialization of sysml models.
+ */
+public class SysMLAPIAccess {
+
+ private SysMLAccess sysmlAccess;
+ private String repositoryURL;
+
+ private EObjectUUIDTracker tracker = new EObjectUUIDTracker();
+
+ /* package */ SysMLAPIAccess(String apiBasePath, SysMLAccess sysmlAccess) {
+ this.repositoryURL = apiBasePath;
+ this.sysmlAccess = sysmlAccess;
+ }
+
+ /**
+ * Sets the api base path for the repository
+ *
+ * @param apiBasePath
+ */
+ public void setApibasePath(String apiBasePath) {
+ this.repositoryURL = apiBasePath;
+ }
+
+ /**
+ * Publishes to the repository the model elements rooted in a named element
+ *
+ * @param element root element of the model
+ * @param projectName if null a new project is created named after the {@code element} otherwise it is used as the name of the project to create or update
+ * @param branchName if null the default branch is used otherwise the model is written to this branch of the project.
+ * @param includeDerievd include derived properties
+ */
+ public void publish(Element element, String projectName, String branchName, boolean includeDerievd) {
+ assert repositoryURL != null: "ERROR: API base path is not set";
+ if (!sysmlAccess.isInputResource(element.eResource())) {
+ throw new IllegalArgumentException("ERROR:'" + element.getQualifiedName() + "' is a library element");
+ } else {
+ String remoteProjectName = projectName == null? element.getDeclaredName() : projectName;
+
+ ApiElementProcessingFacade processingFacade = this.getApiElementProcessingFacade(remoteProjectName, branchName, includeDerievd);
+ processingFacade.getTraversal().visit(element);
+ processingFacade.commit(element);
+ }
+ }
+
+ /**
+ * Publishes to the repository the resource's contents
+ *
+ * @param element resource to be published
+ * @param projectName if null a new project is created named after the {@code element} otherwise it is used as the name of the project to create or update
+ * @param branchName if null the default branch is used otherwise the model is written to this branch of the project.
+ * @param includeDerievd include derived properties
+ */
+ public void publish(Resource resource, String projectName, String branchName, boolean includeDerievd) {
+ EObject first = resource.getContents().getFirst();
+ if (first instanceof Element) {
+ publish((Element) first, projectName, branchName, includeDerievd);
+ }
+ }
+
+ /**
+ * Publishes to the repository the model elements rooted in a named element
+ *
+ * @param element qualified name of the root element
+ * @param projectName if null a new project is created named after the {@code element} otherwise it is used as the name of the project to create or update
+ * @param branchName if null the default branch is used otherwise the model is written to this branch of the project.
+ * @param includeDerievd include derived properties
+ */
+ public void publish(String elementName, String projectName, String branchName, boolean includeDerievd) {
+ Element element = sysmlAccess.resolve(elementName);
+
+ if (element == null) {
+ throw new NoSuchElementException("ERROR:Couldn't resolve reference to Element '" + elementName);
+ }
+
+ publish(element, projectName, branchName, includeDerievd);
+ }
+
+ /**
+ * Downloads previously published models from a project in the repository.
+ *
+ * @param projectDescriptor to specify the project and the branch to be used.
+ *
+ * @return list of loaded resources
+ */
+ public List load(APIProjectDescriptor projectDescriptor) {
+
+ final ProjectRepository repository = new ProjectRepository(repositoryURL);
+
+ final RemoteProject project = projectDescriptor.getBranchId().map(repository::getProjectById)
+ .or(() -> projectDescriptor.getProjectName().map(repository::getProjectByName))
+ .orElseThrow(() -> new NoSuchElementException("ERROR:Project doesn't exist"));
+
+
+ final RemoteBranch branch;
+
+ if (projectDescriptor.getBranchId().isEmpty() && projectDescriptor.getBranchName().isEmpty()) {
+ branch = project.getDefaultBranch();
+ if (branch == null) {
+ throw new NoSuchElementException("ERROR:Project has no default branch");
+ }
+ } else {
+ branch = projectDescriptor.getBranchId().map(id -> project.getBranch(UUID.fromString(id)))
+ .or(() -> projectDescriptor.getBranchName().map(project::getBranch)).orElseThrow(() -> new NoSuchElementException("ERROR:Branch doesn't exist"));
+ }
+
+ return load(branch);
+ }
+
+ private List load(RemoteBranch branch) {
+ assert repositoryURL != null: "ERROR: API base path is not set";
+
+ Revision headRevision = branch.getHeadRevision();
+ if (!headRevision.isRemote()) {
+ throw new NoSuchElementException("ERROR:Branch has no head commit");
+ }
+
+ if (!tracker.isLibraryTracked()) {
+ System.out.println("Caching library UUIDs...");
+ tracker.trackLibraryUUIDs(sysmlAccess.getLibraryResources());
+ }
+
+ tracker.clear();
+ List inputResources = sysmlAccess.getInputResources();
+ //UUIDS coming from resources that were added later in time will shadow previous ones
+ tracker.trackLocalUUIDs(inputResources);
+
+ System.out.println("Downloading model...");
+ APIModel model = headRevision.fetchRemote();
+
+ EMFModelRefresher modelRefresher = new EMFModelRefresher(model, tracker);
+ EMFModelDelta delta = modelRefresher.create();
+ modelRefresher.getIssues().forEach(System.out::println);
+
+ return delta.getProjectRootsAsNamespaces().stream().map(rootNs -> {
+ Resource resource = sysmlAccess.createResource(rootNs.toString() + SysMLAccess.SYSML_EXTENSION);
+ resource.getContents().add(rootNs);
+ sysmlAccess.addInputResource(resource);
+ sysmlAccess.addResourceToIndex(resource);
+ return resource;
+ }).toList();
+ }
+
+
+ protected ApiElementProcessingFacade getApiElementProcessingFacade(String modelName, String branchName, boolean includeDerived) {
+ ApiElementProcessingFacade processingFacade = new ApiElementProcessingFacade(modelName, branchName, repositoryURL);
+ processingFacade.setIsIncludeDerived(includeDerived);
+ processingFacade.setTraversal(new Traversal(processingFacade));
+ return processingFacade;
+ }
+
+ /**
+ * Creates a JSON representation of the abstract syntax tree rooted in the named element.
+ *
+ * @param root root Element
+ * @param includeDerived include derived fields in the output
+ * @param asDelta wrap the elements in a delta as additions for direct REST API use
+ * @return JSON representation of the model
+ */
+ public String toJson(Element root, boolean includeDerived, boolean asDelta) {
+ JsonElementProcessingFacade jsonFacade = new JsonElementProcessingFacade();
+ jsonFacade.setIsIncludeDerived(includeDerived);
+ Traversal traversal = new Traversal(jsonFacade);
+ jsonFacade.setTraversal(traversal);
+ traversal.visit(root);
+ return jsonFacade.toJson(asDelta);
+ }
+
+ /**
+ * Queries projects stored in the repository
+ *
+ * @return list of stored projects
+ */
+ public List getProjects() {
+ final ProjectRepository repository = new ProjectRepository(repositoryURL);
+ return repository.getProjects();
+ }
+
+ /**
+ * Configuration for targeting a project and project branch in the repository.
+ *
+ * The {@code projectName} and {@code projectId} are mutually exclusive.
+ * The {@code branchName} and {@code branchId} are mutually exclusive.
+ */
+ public static class APIProjectDescriptor {
+ private String projectName;
+ private String projectId;
+ private String branchName;
+ private String branchId;
+
+ public APIProjectDescriptor projectId(String projectId) {
+ assert projectName == null: "ERROR:Project name and id cannot be provided at the same time";
+ this.projectId = projectId;
+ return this;
+ }
+
+ public APIProjectDescriptor projectName(String projectName) {
+ assert projectId == null: "ERROR:Project name and id cannot be provided at the same time";
+ this.projectName = projectName;
+ return this;
+ }
+
+ public APIProjectDescriptor branchName(String branchName) {
+ assert branchId == null: "ERROR:Branch name and id cannot be provided at the same time";
+ this.branchName = branchName;
+ return this;
+ }
+
+ public APIProjectDescriptor pranchId(String branchId) {
+ assert branchName == null: "ERROR:Branch name and id cannot be provided at the same time";
+ this.branchId = branchId;
+ return this;
+ }
+
+ public Optional getProjectName() {
+ return Optional.ofNullable(projectName);
+ }
+
+ public Optional getProjectId() {
+ return Optional.ofNullable(projectId);
+ }
+
+ public Optional getBranchName() {
+ return Optional.ofNullable(branchName);
+ }
+
+ public Optional getBranchId() {
+ return Optional.ofNullable(branchId);
+ }
+ }
+}
diff --git a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLAccess.java b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLAccess.java
new file mode 100644
index 000000000..ce9ff8fd8
--- /dev/null
+++ b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLAccess.java
@@ -0,0 +1,417 @@
+/**
+ * SysML 2 Pilot Implementation
+ * Copyright (C) 2025 Model Driven Solutions, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * @license LGPL-3.0-or-later
+ *
+ * Contributors:
+ * Laszlo Gati, MDS
+ */
+package org.omg.sysml.xtext.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.parser.IParseResult;
+import org.eclipse.xtext.resource.IEObjectDescription;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
+import org.eclipse.xtext.scoping.IGlobalScopeProvider;
+import org.eclipse.xtext.scoping.IScope;
+import org.eclipse.xtext.service.OperationCanceledError;
+import org.eclipse.xtext.util.CancelIndicator;
+import org.eclipse.xtext.validation.CheckMode;
+import org.eclipse.xtext.validation.IResourceValidator;
+import org.eclipse.xtext.validation.Issue;
+import org.omg.kerml.xtext.KerMLStandaloneSetup;
+import org.omg.kerml.xtext.library.ILibraryIndexProvider;
+import org.omg.kerml.xtext.naming.KerMLQualifiedNameConverter;
+import org.omg.kerml.xtext.xmi.KerMLxStandaloneSetup;
+import org.omg.sysml.lang.sysml.Element;
+import org.omg.sysml.lang.sysml.SysMLFactory;
+import org.omg.sysml.lang.sysml.SysMLPackage;
+import org.omg.sysml.lang.sysml.util.SysMLLibraryUtil;
+import org.omg.sysml.util.SysMLUtil;
+import org.omg.sysml.xtext.SysMLStandaloneSetup;
+import org.omg.sysml.xtext.xmi.SysMLxStandaloneSetup;
+
+import com.google.common.base.Predicates;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * This is an API that enables building batch applications
+ * for parsing and validation of sysml and kerml models
+ * by setting up the language infrastructure and reading the library.
+ * The API provides access to the underlying EMF infrastructure as well to enable
+ * model processing. {@link SysMLAccess#getAPIAccess() } can be used to construct an
+ * interface for reading and writing models from/to the standard SysML REST API.
+ */
+public class SysMLAccess extends SysMLUtil {
+ public static final String KERNEL_LIBRARIES_DIRECTORY = "Kernel Libraries";
+ public static final String SYSTEMS_LIBRARY_DIRECTORY = "Systems Library";
+ public static final String DOMAIN_LIBRARIES_DIRECTORY = "Domain Libraries";
+
+ public static final String KERML_EXTENSION = ".kerml";
+ public static final String SYSML_EXTENSION = ".sysml";
+
+ public static final String KERMLX_EXTENSION = ".kermlx";
+ public static final String SYSMLX_EXTENSION = ".sysmlx";
+
+ private Resource dummyResource;
+
+ @Inject
+ protected IGlobalScopeProvider scopeProvider;
+
+ @Inject
+ protected KerMLQualifiedNameConverter qualifiedNameConverter;
+
+ @Inject
+ private ILibraryIndexProvider libraryIndexCache;
+
+ @Inject
+ protected IResourceValidator validator;
+ private SysMLAPIAccess apiAccess;
+
+ @Inject
+ public SysMLAccess() {
+ super();
+ }
+
+ protected SysMLAccess(ResourceDescriptionsData resourceDescriptionData) {
+ super(resourceDescriptionData);
+ }
+
+ /**
+ * Provides access for the library index.
+ *
+ * @return Library index provider
+ */
+ public ILibraryIndexProvider getLibraryIndexCache() {
+ return libraryIndexCache;
+ }
+
+ /**
+ * Initializes the language infrastructure for loading .kermlx and .sysmlx models.
+ */
+ public void setupXMISupport() {
+ addExtension(KERMLX_EXTENSION);
+ addExtension(SYSMLX_EXTENSION);
+ KerMLxStandaloneSetup.doSetup();
+ SysMLxStandaloneSetup.doSetup();
+ }
+
+ /**
+ * Loads the library from the specified directory.
+ * Use {@link SysMLAccess#setModelLibraryDirectory(String)} to set the directory path.
+ *
+ * @throws IOException
+ */
+ public void loadLibrary() throws IOException {
+ doLoadLibrary(getModelLibraryDirectory());
+ }
+
+ protected void doLoadLibrary(String path) throws IOException {
+ if (path != null) {
+ this.readAll(path + KERNEL_LIBRARIES_DIRECTORY, false, KERML_EXTENSION);
+ this.readAll(path + SYSTEMS_LIBRARY_DIRECTORY, false, SYSML_EXTENSION);
+ this.readAll(path + DOMAIN_LIBRARIES_DIRECTORY, false, SYSML_EXTENSION);
+ }
+ }
+
+ protected Resource getDummyResource() {
+ if (this.dummyResource == null) {
+ this.dummyResource = this.createResource("dummy" + SYSML_EXTENSION);
+ this.dummyResource.getContents().add(SysMLFactory.eINSTANCE.createNamespace());
+ }
+ return this.dummyResource;
+ }
+
+ /**
+ * Returns the root element from a resource
+ *
+ * @param resource resource with the root element
+ * @return root element
+ */
+ public Element getRootElement(Resource resource) {
+ if (resource instanceof XtextResource xtextResource) {
+ final IParseResult result = xtextResource.getParseResult();
+ return result == null? null: (Element)result.getRootASTElement();
+ } else {
+ EList contents = resource.getContents();
+ return contents.isEmpty()? null: (Element)contents.get(0);
+ }
+ }
+
+ /**
+ * Resolves the given name from the loaded resources.
+ *
+ * @param name name to resolve
+ * @return resolved {@link Element} or null if name cannot be resolved
+ */
+ public Element resolve(String name) {
+ IScope scope = scopeProvider.getScope(
+ this.getDummyResource(),
+ SysMLPackage.eINSTANCE.getNamespace_Member(),
+ Predicates.alwaysTrue());
+ IEObjectDescription description = scope.getSingleElement(
+ this.qualifiedNameConverter.toQualifiedName(name));
+ if (description == null) {
+ return null;
+ } else {
+ EObject object = description.getEObjectOrProxy();
+ return object instanceof Element? (Element)object: null;
+ }
+ }
+
+ /**
+ * Loads, parses and validates a model file or a directory (recursively) with a set of model files.
+ *
+ * @param file file to parse or directory containing model files
+ * @param isInput whether the file(s) read are to be considered input resources
+ * @return result of the parsing/validation
+ * @throws IOException
+ */
+ public List parseFiles(File file, boolean isInput) throws IOException {
+ List resources = this.readAll(file, isInput);
+ return validateResources(resources);
+ }
+
+
+ /**
+ * Loads, parses and validates a model file or a directory (recursively) with a set of model files.
+ *
+ * @param file file to parse or directory containing model files
+ * @param isInput whether the file(s) read are to be considered input resources
+ * @return result of the parsing/validation
+ * @throws IOException
+ */
+ public List parseFile(String file, boolean isInput) throws IOException {
+ return parseFiles(new File(file), isInput);
+ }
+
+
+ /**
+ * Validates the given resources
+ *
+ * @param resources resources to validate
+ * @return list of results
+ * @throws OperationCanceledError
+ */
+ public List validateResources(List resources) throws OperationCanceledError {
+ final List results = new LinkedList<>();
+ for (var resource: resources) {
+ List issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl);
+ results.add(new SysMLParseResult(getRootElement(resource), issues));
+ }
+ return results;
+ }
+
+ /**
+ * Parses a string that contains a sysml or kerml model.
+ * The {@code resourceURI} identifies the loaded model in the {@code SysMLAccess}.
+ * It is mandatory to use either .sysml or .kerml extension {@code resourceURI}
+ * depending on the input to be parsed.
+ *
+ * @param resourceURI identifier of the parsed model in the {@code SysMLAccess}
+ * @param input string to be parsed
+ * @return results of the parsing
+ * @throws IOException
+ */
+ public SysMLParseResult parse(String resourceURI, String input) throws IOException {
+ assert resourceURI.endsWith(".kerml") || resourceURI.endsWith(".sysml"): "resourceName must use .kerml or .sysml file extension";
+
+ Resource resource = this.createResource(resourceURI);
+ addInputResource(resource);
+ if (resource instanceof XtextResource xtextResource) {
+ xtextResource.reparse(input);
+ addResourceToIndex(xtextResource);
+ } else {
+ //TODO: add warning when resource is not meant to be parsed
+ }
+
+ List issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl);
+ return new SysMLParseResult(getRootElement(resource), issues);
+ }
+
+ /**
+ * Changes the model library directory
+ *
+ * @param directory directory with the standard sysml library
+ */
+ public void setModelLibraryDirectory(String directory) {
+ if (!directory.endsWith("/")) {
+ directory += "/";
+ }
+ SysMLLibraryUtil.setModelLibraryDirectory(directory);
+ }
+
+ /**
+ * @return path to set sysml standard library
+ */
+ public String getModelLibraryDirectory() {
+ return SysMLLibraryUtil.getModelLibraryPath();
+ }
+
+ /**
+ * Returns the {@link SysMLAPIAccess}: a utility for accessing the SysML REST API. With basic read and write functionality.
+ * The instance is lazily created and stored on the first call further calls only modify the {@code apiBasePath}.
+ *
+ * @param apiBasePath API base path for the repository
+ * @return utility for writing/loading the repository
+ */
+ public SysMLAPIAccess getOrCreateAPIAccess(String apiBasePath) {
+ if (apiAccess == null) {
+ this.apiAccess = new SysMLAPIAccess(apiBasePath, this);
+ } else {
+ this.apiAccess.setApibasePath(apiBasePath);
+ }
+ return this.apiAccess;
+ }
+
+ /**
+ * Returns the stored {@link SysMLAPIAccess}. Use {@link SysMLAccess#getOrCreateAPIAccess(String)}
+ * for initialization.
+ *
+ * @return stored {@code SysMLAPIAccess} or null if it isn't initialized
+ */
+ public SysMLAPIAccess getAPIAccess() {
+ return this.apiAccess;
+ }
+
+ /**
+ * Returns a builder for the {@link SysMLAccess}. With more initialization options.
+ *
+ * @return builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Creates a {@link SysMLAccess} instance and initializes the language infrastructure as well as the API Access.
+ *
+ * @param modelLibraryDirectory directory with the standard sysml library
+ * @param apiBasePath API base path for the repository
+ * @return configured SysMLAccess instance
+ */
+ public static SysMLAccess createFullyFeaturedWithAPIAccess(String modelLibraryDirectory, String apiBasePath) {
+ return builder()
+ .libraryPath(modelLibraryDirectory)
+ .apiBasePath(apiBasePath)
+ .xmiSupport()
+ .verbose()
+ .build();
+ }
+
+ /**
+ * Creates a {@link SysMLAccess} instance and initializes the language infrastructure.
+ *
+ * @param modelLibraryDirectory directory with the standard sysml library
+ * @return configured SysMLAccess instance
+ */
+ public static SysMLAccess createFullyFeatured(String modelLibraryDirectory) {
+ return builder()
+ .libraryPath(modelLibraryDirectory)
+ .xmiSupport()
+ .verbose()
+ .build();
+ }
+
+ protected static class SysMLInteractiveAccess extends SysMLAccess {
+
+ @Inject
+ public SysMLInteractiveAccess() {
+ super(new StrictShadowingResourceDescriptionData());
+ }
+ }
+
+ public static class Builder {
+ private boolean interactiveShadowing = false;
+ private String modelLibraryDirectory = SysMLLibraryUtil.DEFAULT_MODEL_LIBRARY_PATH;
+ private boolean withXMISupport = false;
+ private boolean verbose;
+ private String apiBasePath;
+
+ public Builder libraryPath(String modelLibraryDirectory) {
+ this.modelLibraryDirectory = modelLibraryDirectory;
+ return this;
+ }
+
+ public Builder interactiveShadowingSemantics() {
+ this.interactiveShadowing = true;
+ return this;
+ }
+
+ public Builder xmiSupport() {
+ this.withXMISupport = true;
+ return this;
+ }
+
+ public Builder verbose() {
+ this.verbose = true;
+ return this;
+ }
+
+ /**
+ * Sets the api base path. This option also turns on {@link Builder#xmiSupport()}
+ * as it is needed for api usage.
+ *
+ * @param apiBasePath
+ * @return the builder
+ */
+ public Builder apiBasePath(String apiBasePath) {
+ this.apiBasePath = apiBasePath;
+ return this;
+ }
+
+ public SysMLAccess build() {
+ // Note: An EPackage must be registered to be sure the correctly configured
+ // CompositeEValidator is used.
+ EPackage.Registry.INSTANCE.put(SysMLPackage.eNS_URI, SysMLPackage.eINSTANCE);
+
+ KerMLStandaloneSetup.doSetup();
+ Injector injector = new SysMLStandaloneSetup().createInjectorAndDoEMFRegistration();
+
+ final SysMLAccess access;
+ if (interactiveShadowing) {
+ access = injector.getInstance(SysMLInteractiveAccess.class);
+ } else {
+ access = injector.getInstance(SysMLAccess.class);
+ }
+
+ access.addExtension(SYSML_EXTENSION);
+ access.addExtension(KERML_EXTENSION);
+
+ access.setModelLibraryDirectory(modelLibraryDirectory);
+ access.setVerbose(verbose);
+ //to create an instance
+ access.getOrCreateAPIAccess(apiBasePath);
+
+ if (withXMISupport || apiBasePath != null) {
+ access.setupXMISupport();
+ }
+
+ return access;
+ }
+ }
+}
diff --git a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLParseResult.java b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLParseResult.java
new file mode 100644
index 000000000..765725139
--- /dev/null
+++ b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLParseResult.java
@@ -0,0 +1,122 @@
+/*****************************************************************************
+ * SysML 2 Pilot Implementation
+ * Copyright (c) 2019, 2020 Model Driven Solutions, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of theGNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * @license LGPL-3.0-or-later
+ *
+ * Contributors:
+ * Ed Seidewitz
+ *
+ *****************************************************************************/
+package org.omg.sysml.xtext.util;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.xtext.diagnostics.Severity;
+import org.eclipse.xtext.validation.Issue;
+import org.omg.sysml.lang.sysml.Element;
+import org.omg.sysml.lang.sysml.Namespace;
+import org.omg.sysml.util.SysMLUtil;
+
+public class SysMLParseResult {
+
+ private Element rootElement = null;
+ private List issues = null;
+ private Exception exception = null;
+
+ public SysMLParseResult(Element rootElement, List issues) {
+ this.rootElement = rootElement;
+ this.issues = issues;
+ }
+
+ public SysMLParseResult(Exception exception) {
+ this.exception = exception;
+ }
+
+ public Element getRootElement() {
+ return this.rootElement;
+ }
+
+ public List getIssues() {
+ return this.issues == null? Collections.emptyList(): this.issues;
+ }
+
+ public List getSyntaxErrors() {
+ return this.getIssues().stream().filter(Issue::isSyntaxError).collect(Collectors.toList());
+ }
+
+ public List getSemanticErrors() {
+ return this.getIssues().stream().
+ filter(issue->!issue.isSyntaxError() && issue.getSeverity() == Severity.ERROR).
+ collect(Collectors.toList());
+ }
+
+ public List getWarnings() {
+ return this.getIssues().stream().
+ filter(issue->issue.getSeverity().equals(Severity.WARNING)).
+ collect(Collectors.toList());
+ }
+
+ public boolean hasErrors() {
+ return this.getIssues().stream().anyMatch(issue->issue.getSeverity() == Severity.ERROR);
+ }
+
+ public boolean hasWarnings() {
+ return this.getIssues().stream().anyMatch(issue->issue.getSeverity() == Severity.WARNING);
+ }
+
+ public Exception getException() {
+ return this.exception;
+ }
+
+ public String formatRootElement() {
+ Element rootElement = this.getRootElement();
+ return rootElement == null? "":
+ !(rootElement instanceof Namespace) || rootElement.getOwner() != null?
+ SysMLUtil.formatElement(rootElement):
+ ((Namespace)rootElement).getOwnedMember().stream().
+ map(SysMLUtil::formatElement).
+ collect(Collectors.joining());
+ }
+
+ public String formatIssues() {
+ return SysMLUtil.formatList(this.issues);
+ }
+
+ public String formatException() {
+ return SysMLUtil.formatException(this.exception);
+ }
+
+ @Override
+ public String toString() {
+ if (this.exception != null) {
+ return this.formatException();
+ } else {
+ List syntaxErrors = this.getSyntaxErrors();
+ if (!syntaxErrors.isEmpty()) {
+ return SysMLUtil.formatList(syntaxErrors);
+ } else {
+ List semanticErrors = this.getSemanticErrors();
+ List warnings = this.getWarnings();
+ String msgs = SysMLUtil.formatList(semanticErrors) + SysMLUtil.formatList(warnings);
+ return semanticErrors.isEmpty()? msgs + this.formatRootElement(): msgs;
+ }
+ }
+ }
+
+}
diff --git a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLRepositoryLoadUtil.java b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLRepositoryLoadUtil.java
index a5953972f..7fc419ab9 100644
--- a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLRepositoryLoadUtil.java
+++ b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/util/SysMLRepositoryLoadUtil.java
@@ -144,23 +144,23 @@ public void load() throws UnsupportedOperationException, ApiException {
return;
}
- System.out.println("Reading library...");
- readAll(localLibraryPath, false);
-
- //collect ids from library
- System.out.println("Tracking library UUIDs...");
- EObjectUUIDTracker tracker = new EObjectUUIDTracker();
- tracker.trackLibraryUUIDs(getLibraryResources());
-
- System.out.println("Downloading project...");
- Revision headRevision = branch.getHeadRevision();
- APIModel remote = headRevision.fetchRemote();
- EMFModelRefresher modelRefresher = new EMFModelRefresher(remote, tracker);
- EMFModelDelta delta = modelRefresher.create();
- modelRefresher.getIssues().forEach(System.out::println);
- ResourceSet resourceSet = getResourceSet();
-
try {
+ System.out.println("Reading library...");
+ readAll(localLibraryPath, false);
+
+ //collect ids from library
+ System.out.println("Tracking library UUIDs...");
+ EObjectUUIDTracker tracker = new EObjectUUIDTracker();
+ tracker.trackLibraryUUIDs(getLibraryResources());
+
+ System.out.println("Downloading project...");
+ Revision headRevision = branch.getHeadRevision();
+ APIModel remote = headRevision.fetchRemote();
+ EMFModelRefresher modelRefresher = new EMFModelRefresher(remote, tracker);
+ EMFModelDelta delta = modelRefresher.create();
+ modelRefresher.getIssues().forEach(System.out::println);
+ ResourceSet resourceSet = getResourceSet();
+
System.out.println("Saving resources...");
delta.apply(resourceSet, URI.createFileURI(targetLocation));
System.out.println("Done.");
diff --git a/org.omg.sysml/src/org/omg/sysml/util/SysMLUtil.java b/org.omg.sysml/src/org/omg/sysml/util/SysMLUtil.java
index 82b2f2bd7..e71e86b17 100644
--- a/org.omg.sysml/src/org/omg/sysml/util/SysMLUtil.java
+++ b/org.omg.sysml/src/org/omg/sysml/util/SysMLUtil.java
@@ -26,13 +26,20 @@
package org.omg.sysml.util;
import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
@@ -41,7 +48,25 @@
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
+import org.omg.sysml.expressions.util.EvaluationUtil;
+import org.omg.sysml.lang.sysml.CalculationUsage;
+import org.omg.sysml.lang.sysml.Element;
+import org.omg.sysml.lang.sysml.Expression;
+import org.omg.sysml.lang.sysml.Feature;
+import org.omg.sysml.lang.sysml.FeatureReferenceExpression;
+import org.omg.sysml.lang.sysml.InvocationExpression;
+import org.omg.sysml.lang.sysml.LiteralBoolean;
+import org.omg.sysml.lang.sysml.LiteralInfinity;
+import org.omg.sysml.lang.sysml.LiteralInteger;
+import org.omg.sysml.lang.sysml.LiteralRational;
+import org.omg.sysml.lang.sysml.LiteralString;
+import org.omg.sysml.lang.sysml.Membership;
+import org.omg.sysml.lang.sysml.MetadataFeature;
+import org.omg.sysml.lang.sysml.OperatorExpression;
+import org.omg.sysml.lang.sysml.OwningMembership;
+import org.omg.sysml.lang.sysml.Relationship;
import org.omg.sysml.lang.sysml.SysMLPackage;
+import org.omg.sysml.lang.sysml.Type;
import com.google.common.base.Predicates;
@@ -60,7 +85,7 @@ public abstract class SysMLUtil {
private final ResourceSet resourceSet;
private final List inputResources = new LinkedList<>();
- private final List extensions = new ArrayList();
+ private final Set extensions = new HashSet<>();
private final ResourceDescriptionsData index;
private boolean isVerbose = true;
@@ -230,21 +255,45 @@ public Resource readResource(final String path) {
*
* @param file the file from which the resources are be read
* @param isInput whether the resources read are to be considered input resources
+ * @param extensions the allowed file extensions
+ * @return
+ * @throws IOException
*/
- public void readAll(final File file, boolean isInput) {
- if (file.isDirectory()) {
- for (File nestedFile: file.listFiles()) {
- this.readAll(nestedFile, isInput);
+ public List readAll(final File file, final boolean isInput, Set extensions) throws IOException {
+ List resources = new LinkedList<>();
+ Files.walk(file.toPath()).forEach(path -> {
+ Resource res = read(path, isInput, extensions);
+ if (res != null) {
+ resources.add(res);
}
- } else {
- final String path = file.getPath();
- if (extensions.stream().anyMatch(path::endsWith)) {
- Resource resource = this.readResource(file.getPath());
- if (isInput) {
- this.addInputResource(resource);
- }
+ });
+ return resources;
+ }
+
+ /**
+ * If the given file has an allowable extension, then read it. Or, if the file is a directory, then
+ * recursively read all the allowable files in it, directly or indirectly.
+ *
+ * @param file the file from which the resources are be read
+ * @param isInput whether the resources read are to be considered input resources
+ * @return
+ * @throws IOException
+ */
+ public List readAll(final File file, final boolean isInput) throws IOException {
+ return readAll(file, isInput, extensions);
+ }
+
+ public Resource read(final Path path, boolean isInput, Set extensions) {
+ final Resource resource;
+ if (extensions.stream().anyMatch(path.toString()::endsWith)) {
+ resource = this.readResource(path.toString());
+ if (isInput) {
+ this.addInputResource(resource);
}
+ } else {
+ resource = null;
}
+ return resource;
}
/**
@@ -254,9 +303,11 @@ public void readAll(final File file, boolean isInput) {
*
* @param path the path from which resources are to be read
* @param isInput whether the resources read are to be considered input resources
+ * @return
+ * @throws IOException
*/
- public void readAll(final String path, boolean isInput) {
- this.readAll(new File(path), isInput);
+ public List readAll(final String path, boolean isInput) throws IOException {
+ return this.readAll(new File(path), isInput, this.extensions);
}
/**
@@ -267,11 +318,11 @@ public void readAll(final String path, boolean isInput) {
* @param path the path from which resources are to be read
* @param isInput whether the resources read are to be considered input resources
* @param extension the allowed file extension
+ * @return
+ * @throws IOException
*/
- public void readAll(final String path, boolean isInput, String extension) {
- this.extensions.clear();
- this.addExtension(extension);
- this.readAll(new File(path), isInput);
+ public List readAll(final String path, boolean isInput, String extension) throws IOException {
+ return this.readAll(new File(path), isInput, Set.of(extension));
}
/**
@@ -280,8 +331,9 @@ public void readAll(final String path, boolean isInput, String extension) {
* other paths are considered to be library resources.
*
* @param paths the paths from which resources are to be read
+ * @throws IOException
*/
- public void read(final String... paths) {
+ public void read(final String... paths) throws IOException {
if (paths.length > 0) {
for (int i = 1; i < paths.length; i++) {
this.readAll(paths[i], false);
@@ -312,4 +364,151 @@ public void resolveAllInputResources() {
}
}
+ //Utility for printing out parts of the model in a human readable format
+
+ public static final String INDENT = " ";
+
+ private static String formatRelationship(EClass kind, String shortName, String memberName) {
+ return "[" + kind.getName() +
+ (shortName == null? "": " <" + shortName + ">") +
+ (memberName == null? "": " " + memberName) +
+ "] ";
+ }
+
+ private static String formatRelationship(Relationship relationship) {
+ return relationship == null? "":
+ relationship instanceof Membership && !(relationship instanceof OwningMembership)?
+ formatRelationship(relationship.eClass(),
+ ((Membership)relationship).getMemberShortName(),
+ ((Membership)relationship).getMemberName()):
+ formatRelationship(relationship.eClass(), null, null);
+ }
+
+ private static void formatElement(StringBuilder buffer, String indentation, Element element, String relationshipTag) {
+ buffer.append(indentation + relationshipTag + element.eClass().getName());
+ if (EvaluationUtil.isMetaclassFeature(element)) {
+ formatElement(buffer, " ", ((MetadataFeature)element).getAnnotatedElement().get(0), "");
+ } else {
+ String shortName = element.getDeclaredShortName();
+ String name = nameOf(element);
+ buffer.append(
+ (shortName == null? "": " <" + shortName + ">") +
+ (name == null? "": " " + name) +
+ " (" + element.getElementId() + ")\n");
+ }
+ }
+
+ public static String nameOf(Element element) {
+ if (element == null) {
+ return "";
+ } else if (element instanceof Feature && !((Feature)element).getOwnedFeatureChaining().isEmpty()) {
+ String name = "";
+ for (Feature chainingFeature: ((Feature)element).getChainingFeature()) {
+ String nextName = chainingFeature.getName();
+ if (nextName == null) {
+ nextName = "";
+ }
+ if (name == "") {
+ name = nextName;
+ } else {
+ name += "." + nextName;
+ }
+ }
+ return name;
+ } else {
+ return element instanceof LiteralBoolean? Boolean.valueOf(((LiteralBoolean)element).isValue()).toString():
+ element instanceof LiteralString? ((LiteralString)element).getValue().toString():
+ element instanceof LiteralInteger? Integer.valueOf(((LiteralInteger)element).getValue()).toString():
+ element instanceof LiteralRational? Double.valueOf(((LiteralRational)element).getValue()).toString():
+ element instanceof LiteralInfinity? "*":
+ element instanceof FeatureReferenceExpression? nameOf(((FeatureReferenceExpression)element).getReferent()):
+ element instanceof OperatorExpression? ((OperatorExpression)element).getOperator():
+ element instanceof InvocationExpression? nameOf(((InvocationExpression)element).getFunction()):
+ element.getName();
+ }
+ }
+
+ private static void formatExplicitElement(StringBuilder buffer, String indentation, Element element, Relationship relationship) {
+ formatElement(buffer, indentation, element, formatRelationship(relationship));
+ }
+
+ private static void formatImplicitElement(StringBuilder buffer, String indentation, Element element, EClass kind) {
+ formatElement(buffer, indentation, element, formatRelationship(kind, null, "(implicit)"));
+ }
+
+ private static void formatTree(StringBuilder buffer, String indentation, Element element, Relationship relationship) {
+ formatExplicitElement(buffer, indentation, element, relationship);
+ if (element instanceof Expression && !(element instanceof CalculationUsage)) {
+ for (Element output: ((Expression)element).getOutput()) {
+ if (output.getOwner() == element) {
+ formatExplicitElement(buffer, indentation + SysMLUtil.INDENT, output, output.getOwningMembership());
+ }
+ }
+ } else {
+ if (element instanceof Type) {
+ TypeUtil.forEachImplicitGeneralTypeOf((Type)element, (kind, supertype)->
+ formatImplicitElement(buffer, indentation + SysMLUtil.INDENT, supertype, kind)
+ );
+ }
+
+ for (Relationship subrelationship: element.getOwnedRelationship()) {
+ for (Element relatedElement: subrelationship.getRelatedElement()) {
+ if (relatedElement != element) {
+ if (relatedElement.getOwningRelationship() == subrelationship) {
+ formatTree(buffer, indentation + SysMLUtil.INDENT, relatedElement, subrelationship);
+ } else {
+ formatExplicitElement(buffer, indentation + SysMLUtil.INDENT, relatedElement, subrelationship);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static String formatElement(Element element) {
+ StringBuilder buffer = new StringBuilder();
+ formatExplicitElement(buffer, "", element, null);
+ return buffer.toString();
+ }
+
+ public static String formatTree(Element element) {
+ StringBuilder buffer = new StringBuilder();
+ formatTree(buffer, "", element, null);
+ return buffer.toString();
+ }
+
+ public static String formatList(List list) {
+ StringBuilder buffer = new StringBuilder();
+ list.stream().map(x->x.toString() + "\n").forEachOrdered(buffer::append);
+ return buffer.toString();
+ }
+
+ public static String formatException(Exception exception) {
+ StringWriter writer = new StringWriter();
+ exception.printStackTrace(new PrintWriter(writer));
+ return writer.toString();
+ }
+
+ public static String formatMembershipList(List membership) {
+ return membership.stream().
+ map(Membership::getMemberElement).
+ sorted(SysMLUtil::compare).
+ map(SysMLUtil::formatElement).
+ collect(Collectors.joining());
+ }
+
+ public static int compare(Element element1, Element element2) {
+ String humanId1 = element1.getDeclaredShortName();
+ String humanId2 = element2.getDeclaredShortName();
+ String name1 = element1.getName();
+ String name2 = element2.getName();
+ return name1 != null && name2 != null? name1.compareToIgnoreCase(name2):
+ name1 == null && name2 != null? -1:
+ name1 != null && name2 == null? 1:
+ humanId1 != null && humanId2 != null? humanId1.compareToIgnoreCase(humanId2):
+ humanId1 == null && humanId2 != null? -1:
+ humanId1 != null && humanId2 == null? 1:
+ 0;
+ }
+
}