diff --git a/README.md b/README.md
index c57ba7937..ae23c7d52 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,7 @@ Publications:
- Combine components to form a ROS System
- [Create manually a new RosSystem description](docu/RosSystemModelDescription.md)
+ - [Visualize a system using PlantUML](docu/PlantUML.md)
- Examples:
- [Simple publisher-subscriber](docu/Example_PubSub.md)
diff --git a/docu/PlantUML.md b/docu/PlantUML.md
new file mode 100644
index 000000000..1e2f0034b
--- /dev/null
+++ b/docu/PlantUML.md
@@ -0,0 +1,8 @@
+## System Models visualization
+
+The visualization of the models is built on top of the [PlantUML](https://plantuml.com/eclipse) viewer for Eclipse. To install this plugin the Eclipse Marketplace can be used. This tool can be easily opened under the menu Help->Eclipse Marketplace. Then Search the "PlantUML plugin" and install it.
+
+The RosTooling will generate for every rossystem file a new PlaUML textual model compatible with the viewer. By default, the RosSystem compiler creates for every valid system model a file under src-gen/**SystemName**/resources/ called **SystemName**.puml.
+
+The file can be opened with a standard textual editor and the corresponding model can be visualized by opening the visualizer, under "Window"->"Show View"->"Other" and searching for "PlantUML".
+:bangbang the file with the extension *.puml must be open, otherwise, the visualizer will not detect it.
diff --git a/plugins/de.fraunhofer.ipa.ros.feature/feature.xml b/plugins/de.fraunhofer.ipa.ros.feature/feature.xml
index 8d90d5703..3c88c1a73 100644
--- a/plugins/de.fraunhofer.ipa.ros.feature/feature.xml
+++ b/plugins/de.fraunhofer.ipa.ros.feature/feature.xml
@@ -66,135 +66,82 @@ POSSIBILITY OF SUCH DAMAGE.
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+ version="3.0.0.qualifier"/>
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/.classpath b/plugins/de.fraunhofer.ipa.ros.sirius/.classpath
new file mode 100644
index 000000000..39810b7d6
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/.project b/plugins/de.fraunhofer.ipa.ros.sirius/.project
new file mode 100644
index 000000000..1cb0d20a5
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/.project
@@ -0,0 +1,28 @@
+
+
+ de.fraunhofer.ipa.ros.sirius
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/META-INF/MANIFEST.MF b/plugins/de.fraunhofer.ipa.ros.sirius/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..e7b9c2dfa
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: de.fraunhofer.ipa.ros.sirius;singleton:=true
+Bundle-Version: 3.0.0.qualifier
+Bundle-Activator: de.fraunhofer.ipa.ros.sirius.Activator
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.sirius,
+ org.eclipse.sirius.common.acceleo.aql,
+ de.fraunhofer.ipa.ros,
+ org.eclipse.ui.workbench,
+ org.eclipse.ui.ide,
+ org.eclipse.sirius.common,
+ org.eclipse.sirius.diagram.ui,
+ de.fraunhofer.ipa.rossystem
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-19
+Bundle-Vendor: Fraunhofer IPA
+Automatic-Module-Name: de.fraunhofer.ipa.ros.sirius
+Export-Package: de.fraunhofer.ipa.ros.sirius
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/build.properties b/plugins/de.fraunhofer.ipa.ros.sirius/build.properties
new file mode 100644
index 000000000..ec79d6f85
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/build.properties
@@ -0,0 +1,8 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ description/,\
+ icons/,\
+ plugin.properties,\
+ plugin.xml
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/description/ros.odesign b/plugins/de.fraunhofer.ipa.ros.sirius/description/ros.odesign
new file mode 100644
index 000000000..3284da905
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/description/ros.odesign
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/action_icon.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/action_icon.png
new file mode 100644
index 000000000..9c55be371
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/action_icon.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/component.gif b/plugins/de.fraunhofer.ipa.ros.sirius/icons/component.gif
new file mode 100644
index 000000000..38c86d700
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/component.gif differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/component.svg b/plugins/de.fraunhofer.ipa.ros.sirius/icons/component.svg
new file mode 100644
index 000000000..a0833a9f8
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/icons/component.svg
@@ -0,0 +1,85 @@
+
+
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/parameters.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/parameters.png
new file mode 100644
index 000000000..d416b0639
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/parameters.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/parameters_scale.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/parameters_scale.png
new file mode 100644
index 000000000..dc7f646e4
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/parameters_scale.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/ros_logo.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/ros_logo.png
new file mode 100644
index 000000000..3362fc8c8
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/ros_logo.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/service_icon.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/service_icon.png
new file mode 100644
index 000000000..f12579237
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/service_icon.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/tools.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/tools.png
new file mode 100644
index 000000000..eedac5f3e
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/tools.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/icons/topic_icon.png b/plugins/de.fraunhofer.ipa.ros.sirius/icons/topic_icon.png
new file mode 100644
index 000000000..f46018756
Binary files /dev/null and b/plugins/de.fraunhofer.ipa.ros.sirius/icons/topic_icon.png differ
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/plugin.properties b/plugins/de.fraunhofer.ipa.ros.sirius/plugin.properties
new file mode 100644
index 000000000..3d2dd03b6
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/plugin.properties
@@ -0,0 +1,3 @@
+pluginName = de.fraunhofer.ipa.ros.sirius
+providerName = Fraunhofer IPA
+viewpointName = MyViewpoint
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/plugin.xml b/plugins/de.fraunhofer.ipa.ros.sirius/plugin.xml
new file mode 100644
index 000000000..d0f3d8277
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/plugin.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/pom.xml b/plugins/de.fraunhofer.ipa.ros.sirius/pom.xml
new file mode 100644
index 000000000..a32cf1464
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/pom.xml
@@ -0,0 +1,12 @@
+
+ 4.0.0
+
+ de.fraunhofer.ipa.ros
+ de.fraunhofer.ipa.ros.parent
+ 2.0.0-SNAPSHOT
+ ../de.fraunhofer.ipa.ros.parent/pom.xml
+
+ de.fraunhofer.ipa.ros.sirius
+ eclipse-plugin
+
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/src/de/fraunhofer/ipa/ros/sirius/Activator.java b/plugins/de.fraunhofer.ipa.ros.sirius/src/de/fraunhofer/ipa/ros/sirius/Activator.java
new file mode 100644
index 000000000..34c320476
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/src/de/fraunhofer/ipa/ros/sirius/Activator.java
@@ -0,0 +1,66 @@
+package de.fraunhofer.ipa.ros.sirius;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.sirius.business.api.componentization.ViewpointRegistry;
+import org.eclipse.sirius.viewpoint.description.Viewpoint;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+ // The plug-in ID
+ public static final String PLUGIN_ID = "de.fraunhofer.ipa.ros.sirius";
+
+ // The shared instance
+ private static Activator plugin;
+
+ private static Set viewpoints;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ viewpoints = new HashSet();
+ viewpoints.addAll(ViewpointRegistry.getInstance().registerFromPlugin(PLUGIN_ID + "/description/ros.odesign"));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ if (viewpoints != null) {
+ for (final Viewpoint viewpoint: viewpoints) {
+ ViewpointRegistry.getInstance().disposeFromPlugin(viewpoint);
+ }
+ viewpoints.clear();
+ viewpoints = null;
+ }
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+}
diff --git a/plugins/de.fraunhofer.ipa.ros.sirius/src/de/fraunhofer/ipa/ros/sirius/Services.java b/plugins/de.fraunhofer.ipa.ros.sirius/src/de/fraunhofer/ipa/ros/sirius/Services.java
new file mode 100644
index 000000000..b66fddb9e
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.sirius/src/de/fraunhofer/ipa/ros/sirius/Services.java
@@ -0,0 +1,17 @@
+package de.fraunhofer.ipa.ros.sirius;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * The services class used by VSM.
+ */
+public class Services {
+
+ /**
+ * See http://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.sirius.doc%2Fdoc%2Findex.html&cp=24 for documentation on how to write service methods.
+ */
+ public EObject myService(EObject self, String arg) {
+ // TODO Auto-generated code
+ return self;
+ }
+}
diff --git a/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/PlantUMLCompiler.xtend b/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/PlantUMLCompiler.xtend
new file mode 100644
index 000000000..8562d882c
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/PlantUMLCompiler.xtend
@@ -0,0 +1,86 @@
+package de.fraunhofer.ipa.rossystem.generator
+
+import system.System
+import com.google.inject.Inject
+import system.RosNode
+import system.impl.RosInterfaceImpl
+import system.RosInterface
+import system.impl.RosSystemConnectionImpl
+
+class PlantUMLCompiler{
+
+ @Inject extension GeneratorHelpers
+
+ def compile_plantuml(System system) '''«init_pkg()»
+@startuml
+
+/'SUBSYSTEMS'/
+«FOR subsystem:system.subsystems»
+component «subsystem.name» {
+«FOR component:getNodes(subsystem)»
+«compile_ports(component)»
+«ENDFOR» }
+«ENDFOR»
+
+«FOR component:getNodes(system)»
+«compile_ports(component)»
+«ENDFOR»
+«FOR connection:system.connections» «get_connection_port((connection as RosSystemConnectionImpl).from)» --> «get_connection_port((connection as RosSystemConnectionImpl).to)»
+«ENDFOR»
+
+@enduml'''
+
+
+ def compile_ports(RosNode component)'''
+ component «(component as RosNode).name» {
+
+ /' PORTS DEFINED AS AVAILABLE IN THE ROSSYSTEM FILE '/
+ «FOR port:(component as RosNode).rosinterfaces»
+ «IF port_type(port)=="INPUT"» portin «get_valid_name(component.name, port.name)» as "«port.name»"«
+ IF (port as RosInterfaceImpl).reference.toString.contains("RosSubscriberReference")» #blue«ENDIF»«
+ IF (port as RosInterfaceImpl).reference.toString.contains("RosServiceServerReference")» #orange«ENDIF»«
+ IF (port as RosInterfaceImpl).reference.toString.contains("RosActionServerReference")» #green«ENDIF»«ENDIF»
+ «IF port_type(port)=="OUTPUT"» portout «get_valid_name(component.name, port.name)» as "«port.name»"«
+ IF (port as RosInterfaceImpl).reference.toString.contains("RosPublisherReference")» #blue«ENDIF»«
+ IF (port as RosInterfaceImpl).reference.toString.contains("RosServiceClientReference")» #orange«ENDIF»«
+ IF (port as RosInterfaceImpl).reference.toString.contains("RosActionClientReference")» #green«ENDIF»«ENDIF»
+ «ENDFOR»
+
+ /' PORTS FROM THE ORIGINAL NODE '/
+««« «FOR sub:(component as RosNode).from.subscriber» portin «get_valid_name(component.name, sub.name)» as "«sub.name»" #line:blue
+««« «ENDFOR»
+««« «FOR ss:(component as RosNode).from.serviceserver» portin «get_valid_name(component.name, ss.name)» as "«ss.name»" #line:orange
+««« «ENDFOR»
+««« «FOR acts:(component as RosNode).from.actionserver» portin «get_valid_name(component.name, acts.name)» as "«acts.name»" #line:green
+««« «ENDFOR»
+««« «FOR pub:(component as RosNode).from.publisher» portout «get_valid_name(component.name, pub.name)» as "«pub.name»" #line:blue
+««« «ENDFOR»
+««« «FOR sc:(component as RosNode).from.serviceclient» portout «get_valid_name(component.name, sc.name)» as "«sc.name»" #line:orange
+««« «ENDFOR»
+««« «FOR actc:(component as RosNode).from.actionclient» portout «get_valid_name(component.name, actc.name)» as "«actc.name»" #line:green«ENDFOR»
+ }
+
+ '''
+
+ def String port_type (RosInterface rosinterface){
+ if ((rosinterface as RosInterfaceImpl).reference.toString.matches
+ (".*RosSubscriberReferenceImpl.*|.*RosServiceServerReference.*|.*RosActionServerReference.*")){
+ return "INPUT"
+ }else {
+ return "OUTPUT"
+ }
+ }
+
+ def get_valid_name (String componentName, String PortName){
+ val identifier = (componentName+"."+PortName).replace("/","_").replace("~","_")
+ return identifier
+ }
+
+ def get_connection_port (RosInterface port){
+ val componentName=(port.eContainer as RosNode).name
+ return get_valid_name (componentName, port.name)
+ }
+}
+
+
+
diff --git a/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/RosSystemGenerator.xtend b/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/RosSystemGenerator.xtend
index 7d8132130..44a260392 100644
--- a/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/RosSystemGenerator.xtend
+++ b/plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/RosSystemGenerator.xtend
@@ -23,6 +23,7 @@ class RosSystemGenerator extends AbstractGenerator {
@Inject extension PackageXmlCompiler
@Inject extension CMakeListsCompiler
@Inject extension READMECompiler
+ @Inject extension PlantUMLCompiler
override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
var yaml_gen = false
@@ -31,6 +32,10 @@ class RosSystemGenerator extends AbstractGenerator {
system.getName().toLowerCase+"/README.md",
compile_toREADME(system).toString().replace("\t"," ")
)
+ fsa.generateFile(
+ system.getName().toLowerCase+"/resource/" + system.getName().toLowerCase + ".puml",
+ compile_plantuml(system)
+ )
if (system.fromFile.isNullOrEmpty) {
fsa.generateFile(
system.getName().toLowerCase+"/launch/"+system.getName()+".launch.py",