⚠️ The examples in this repository are currently work in progress⚠️
This repository contains a couple of examples that show various aspects of the modelix platform. Not all features of modelix are shown here so this is not a complete demo of everything modelix can do. The primary focus of the examples is to show how you can use modelix to work with language and models defined in MPS outside of MPS using JVM (Java/Kotlin) or web frameworks/tools.
None of the examples try to reuse editors defined in MPS. If your goal is to reuse MPS editors as is then modelix itself ships with a projector integration to achieve this.
While all the examples use the same language defined in MPS they are not meant as one complete example but rather as individual parts. The purpose of the examples is to give inspiration of what is possible with modelix and make you think and envision your own use cases.
The repository is a single gradle project to make building everything at once easy. The examples are organized by the technology they use into the various sub-folders:
Id / Link | Components/Technologies | Description | Status | Folder |
---|---|---|---|---|
1 | MPS + cloud-plugin |
MPS language definition that is used by all examples. The MPS language structure is used to generate a Java API consumed by all examples. | ✅ | MPS |
2 | MPS, api-gen |
Generated Java API from the MPS language. | ✅ | University.Schedule.api |
3 | OpenAPI | A hand-crafted OpenAPI specification that defines domain-specific REST endpoints which expose the model contents. | ✅ | Openapi |
4a | MPS w/ mps-json-bulk-access + Ktor |
An implementation of the OpenAPI that exposes the model contents via REST. Obtains model data from MPS using the mps-json-bulk-access plugin. |
✅ | rest-api-json-bulk |
4b | model-server + Quarkus |
An implementation of the OpenAPI that exposes the model contents REST. Obtains model data from a running model-server . |
✅ | rest-api-model-server |
5 | Angular via REST | A single page app that realizes a read-only dashboard. Can connect to either of the OpenAPI implementations. | ✅ | spa-dashboard-angular |
6 |
❔ + websockets | A web application that allows editing of MPS models and realtime collaboration. | ❌ | collaboration-web-app |
7 |
docker / kubernetes | ❌ | deployment |
Each sub-folder contains its own README.md
with component specific documentation.
To get started with the project we need to set up the gradle project. At the moment most modelix artifacts are stored on the itemis nexus with no access restriction. Some are also stored on GitHub packages.
Unfold for details on how to set up GitHub packages authentication
To access GitHub packaged you need to specify your credentials. First of all you will need to generate a [personal access token](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#authenticating-to-github-packages) with access to GitHub Packages. The project assumes that your username is available as the variable `gpr.user` and the token as `gpr.key`. The easiest way to configure the credentials is copy the example below, paste it into the [`gradle.properties`](gradle.properties) file in the repository and replace the values with your credentials:gpr.user=<your GitHub login>
gpr.key=<your personal access token>
Gradle also supports other locations for specifying these properties.
After you have set up your credentials you can build all examples.
To build all examples via gradle, simply call:
./gradlew build # mac/linux
gradlew.bat build # windows
Once the initial build has completes feel free to inspect the use cases and start components as described for each use case. Alternatively, you can inspect and edit the project with the code editor of your choice.
- The top repository provides
IntelliJ
configurations, - the mps sub-project can be opened using
MPS 2020.3.6
, and - the dashboard is a
WebStorm
project.
This project allows you to run different use cases. Depending on the chosen use case, only a subset of the components in this repository are used.
The full architecture includes components for multiple use cases. One does not need all components to realize individual use cases.
In the following a short overview is given on each component.
-
The MPS Language
The language (meta-model) and model used in all examples.
-
Generated model API (domain API)
An API based on the meta-model generated with the api-gen plugin from modelix.
-
Domain-specific OpenAPI
In this example project, an extra domain-specific API layer is added which is defined in the OpenAPI specification. This layer is meant educational as no noteworthy abstractions from the language itself happen in this definition. It intends to show how one introduces a clearly defined domain-specific abstraction decoupling the language engineering (meta-modeling) and the web development.
We provide two backends (i.e. implementations of the API layer): The
rest-api-json-bulk
andrest-api-model-server
components.For more details, also see the 'OpenAPI of the Courses domain' section in the MPS README.md
-
OpenAPI implementation
This project provides two implementations of the OpenAPI domain abstraction.
-
A. MPS as a source (
rest-api-json-bulk
component)This backend provides access to the model by obtaining the model knowledge directly from a running MPS instance. It is implemented using ktor and connects to the
json-bulk-model-access
plugin running inside of MPS. This component can only provide read only access as thejson-bulk-model-access
is read only.For more details, also see the
rest-api-json-bulk
README.md for details. -
B. model-server as a source (
rest-api-model-server
component)This backend provides access to the model by connecting to a running
modelix model-server
. It is implemented using Quarkus and can provide read access to the underlying model. Additionally, a websocket for push notifications about ongoing model changes is provided. This is realized using websockets exposed by themodel-server
.For more details, also see the
rest-api-model-server
README.md for details.
-
-
Single-page application (SPA) Dashboard
The dashboard provides access to model knowledge through a browser. As it is conforming to the OpenAPI specification, the dashboard is able to obtain the model content from both backend implementations. However, the dashboard is consequently limited by the chosen backend.
For more details, also see the
spa-dashboard-angular
README.md for details.Note: Requires an OpenAPI implementation to obtain model knowledge from.
-
'Real-time' collaboration web application
⚠️ TBD -
Deploying to Docker / Kubernetes
⚠️ TBD
To illustrate different use cases, this section provides a short description of each use case alongside with the required system architecture.
The imaginary domain use-case is a display next to each room that shows the upcoming lectures in that room or a display in the main hall showing all the lectures of the current day. This use case envisions a scenario where a system/service outside of MPS wants to consume the content of models defined in MPS (i.e. read only access).
The dashboard, an angular app that serves the content of a model, implements such a simple application. In this simple case, a user does not need to edit these models from the browser.
There are two variations of this use case:
-
a. No automatic update in the SPA using the simple
rest-api-json-bulk
backend and MPS -
b. With automatic updates in the SPA using the more complex
rest-api-model-server
backend and themodel-server
Note: All gradle commands assume you are in the top level folder of this repository.
To start up the system as described in UC 1a, you first have to have built the entire project:
./gradlew
Once done, you need to start all components involved, these are:
-
MPS: Start
MPS 2020.3.6
without any global plugins and open the project in the mps folder. The gradle build process will have downloaded all plugins needed tomps/build/dependencies
. This includes thejson-bulk-model-access
,api-gen
, andmodelix-cloud-access
. -
API layer: The
rest-api-json-bulk
provides the models from the running MPS instance, simply run in a new terminal (it will be a blocking call):$ ./gradlew rest-api-json-bulk:run
🧾 You can expect output similar to this (unfold to see details)
> Task :rest-api-json-bulk:run 2022-12-07 10:12:38.874 [DefaultDispatcher-worker-11] INFO ktor.application - Autoreload is disabled because the development mode is off. 2022-12-07 10:12:39.009 [DefaultDispatcher-worker-11] INFO ktor.application - Application started in 0.14 seconds. 2022-12-07 10:12:39.131 [DefaultDispatcher-worker-1] INFO ktor.application - Responding at http://0.0.0.0:8090 <===========--> 91% EXECUTING [2m 20s] > :rest-api-json-bulk:run
-
Dashboard: The dashboard itself is a node application which can be run via in a new terminal (it will be a blocking call):
$ ./gradlew spa-dashboard-angular:npmRun
🧾 You can expect output similar to this (unfold to see details)
> Task :spa-dashboard-angular:npmRun > [email protected] ng > ng serve - Generating browser application bundles (phase: setup)... ✔ Browser application bundle generation complete. Initial Chunk Files | Names | Raw Size vendor.js | vendor | 2.47 MB | polyfills.js | polyfills | 318.03 kB | styles.css, styles.js | styles | 211.31 kB | main.js | main | 86.71 kB | runtime.js | runtime | 6.53 kB | | Initial Total | 3.08 MB Build at: 2022-12-07T09:18:02.345Z - Hash: 186b24edf20c1c4a - Time: 13776ms ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** ✔ Compiled successfully. ✔ Browser application bundle generation complete. 5 unchanged chunks Build at: 2022-12-07T09:18:02.740Z - Hash: 186b24edf20c1c4a - Time: 324ms ✔ Compiled successfully. <============-> 95% EXECUTING [29s] > :spa-dashboard-angular:npmRun
-
Explore the dashboard at http://localhost:4200/
Note: Changes to the model in MPS will not automatically synchronize to the dashboard, you will have to manually reload the model.
Note: All gradle commands assume you are in the top level folder of this repository.
To start up the system as described in UC 1b, you first have to have build the entire project:
./gradlew
Once done, you need to start all components involved, these are:
-
modelix model-server: Model knowledge is supplied by the
model-sever
in this use case. To avoid complicated setups, we simply start the model-server in memory and load the model content from the included dump file, all using gradle:./gradlew model-server:run --args="-inmemory -dumpin courses.modelserver.dump"
🧾 You can expect output similar to this (unfold to see details)
./gradlew model-server:run --args="-inmemory -dumpin courses.modelserver.dump" > Task :model-server:run 18:33:16,185 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 18:33:16,186 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 18:33:16,186 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [jar:file:/home/nkoester/.gradle/caches/modules-2/files-2.1/org.modelix/model-server-fatjar/1.3.2/1e6502c0e8282b1fe2c06824ad43f4d7270f20d7/model-server-fatjar-1.3.2.jar!/logback.xml] 18:33:16,194 |-INFO in ch.qos.logback.core.joran.spi.ConfigurationWatchList@f4168b8 - URL [jar:file:/home/nkoester/.gradle/caches/modules-2/files-2.1/org.modelix/model-server-fatjar/1.3.2/1e6502c0e8282b1fe2c06824ad43f4d7270f20d7/model-server-fatjar-1.3.2.jar!/logback.xml] is not of type file 18:33:16,269 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] 18:33:16,270 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [console] 18:33:16,272 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 18:33:16,282 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.modelix] to DEBUG 18:33:16,282 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [console] to Logger[org.modelix] 18:33:16,282 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to INFO 18:33:16,282 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [console] to Logger[ROOT] 18:33:16,282 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration. 18:33:16,283 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@7ff95560 - Registering current configuration as safe fallback point 18:33:16.295 [main] INFO org.modelix.model.server.Main - Max memory (bytes): 32178700288 18:33:16.295 [main] INFO org.modelix.model.server.Main - Max memory (bytes): 32178700288 18:33:16.295 [main] INFO org.modelix.model.server.Main - Server process started 18:33:16.295 [main] INFO org.modelix.model.server.Main - Server process started 18:33:16.295 [main] INFO org.modelix.model.server.Main - In memory: true 18:33:16.295 [main] INFO org.modelix.model.server.Main - In memory: true 18:33:16.296 [main] INFO org.modelix.model.server.Main - Path to secret file: /secrets/modelsecret/modelsecret.txt 18:33:16.296 [main] INFO org.modelix.model.server.Main - Path to secret file: /secrets/modelsecret/modelsecret.txt 18:33:16.296 [main] INFO org.modelix.model.server.Main - Path to JDBC configuration file: null 18:33:16.296 [main] INFO org.modelix.model.server.Main - Path to JDBC configuration file: null 18:33:16.296 [main] INFO org.modelix.model.server.Main - Schema initialization: false 18:33:16.296 [main] INFO org.modelix.model.server.Main - Schema initialization: false 18:33:16.296 [main] INFO org.modelix.model.server.Main - Set values: [] 18:33:16.296 [main] INFO org.modelix.model.server.Main - Set values: [] 18:33:16.296 [main] INFO org.modelix.model.server.Main - Port: 28101 18:33:16.296 [main] INFO org.modelix.model.server.Main - Port: 28101 Values loaded from /home/nkoester/git/modelix/modelix-sample/model-server/courses.modelserver.dump (73) 18:33:16.364 [main] INFO ktor.application - Autoreload is disabled because the development mode is off. 18:33:16.428 [main] INFO ktor.application - Application started in 0.088 seconds. 18:33:16.518 [DefaultDispatcher-worker-1] INFO ktor.application - Responding at http://0.0.0.0:28101 <===========--> 85% EXECUTING [7s] > :model-server:run
-
API layer: The
rest-api-model-server
provides an abstraction of the model from the previously startedmodel-server
, simply run in a new terminal (it will be a blocking call):$ ./gradlew rest-api-model-server:quarkusDev
🧾 You can expect output similar to this (unfold to see details)
$ ./gradlew rest-api-model-server:quarkusDev > Task :rest-api-model-server:quarkusDev Listening for transport dt_socket at address: 5005 Press [h] for more options>NG [8s] Tests paused Press [r] to resume testing, [h] for more options> Press [r] to resume testing, [o] Toggle test output, [h] for more options> __ ____ __ _____ ___ __ ____ ______ --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ 2022-12-07 14:02:16,002 INFO [io.und.websockets] (Quarkus Main Thread) UT026003: Adding annotated server endpoint class org.modelix.sample.restapimodelserver.UpdateSocket for path /updates 2022-12-07 14:02:16,464 INFO [io.quarkus] (Quarkus Main Thread) rest-api-model-server unspecified on JVM (powered by Quarkus 2.14.0.Final) started in 2.922s. Listening on: http://localhost:8090 2022-12-07 14:02:16,464 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. 2022-12-07 14:02:16,465 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, kotlin, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, smallrye-openapi, swagger-ui, vertx, websockets, websockets-client] <============-> 95% EXECUTING [16s] > :rest-api-model-server:quarkusDev
-
Dashboard: The dashboard itself is a node application which can be run via in a new terminal (it will be a blocking call):
$ ./gradlew spa-dashboard-angular:npmRun
🧾 You can expect output similar to this (unfold to see details)
> Task :spa-dashboard-angular:npmRun > [email protected] ng > ng serve - Generating browser application bundles (phase: setup)... ✔ Browser application bundle generation complete. Initial Chunk Files | Names | Raw Size vendor.js | vendor | 2.47 MB | polyfills.js | polyfills | 318.03 kB | styles.css, styles.js | styles | 211.31 kB | main.js | main | 86.71 kB | runtime.js | runtime | 6.53 kB | | Initial Total | 3.08 MB Build at: 2022-12-07T09:18:02.345Z - Hash: 186b24edf20c1c4a - Time: 13776ms ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** ✔ Compiled successfully. ✔ Browser application bundle generation complete. 5 unchanged chunks Build at: 2022-12-07T09:18:02.740Z - Hash: 186b24edf20c1c4a - Time: 324ms ✔ Compiled successfully. <============-> 95% EXECUTING [29s] > :spa-dashboard-angular:npmRun
-
MPS: Start
MPS 2020.3.6
without any global plugins and open the project in the mps folder. The gradle build process will have downloaded all plugins needed tomps/build/dependencies
. This includes thecloud-access
plugin used. -
Explore the dashboard at http://localhost:4200/
Note: Changes to the model in MPS will automatically synchronize to the dashboard