Skip to content
Snippets Groups Projects
Commit e6a68f9d authored by René Schöne's avatar René Schöne
Browse files

Merge branch 'release/1.1.0' into 'main'

Version 1.1.0

See merge request !39
parents 2128755a f219a5e6
Branches main
No related tags found
1 merge request!39Version 1.1.0
Pipeline #17588 passed
Showing
with 283 additions and 132 deletions
pages/docs/img/2022_models/slides.pdf filter=lfs diff=lfs merge=lfs -text
pages/docs/img/2022_models/poster.pdf filter=lfs diff=lfs merge=lfs -text
......@@ -22,11 +22,13 @@ build:
image: openjdk:11
stage: build
script:
- ./gradlew --console=plain --no-daemon assemble jar
- ./gradlew --console=plain --no-daemon assemble testClasses jar
artifacts:
paths:
- "ragconnect.base/build/libs/ragconnect-*.jar"
- "ragconnect.base/src/gen"
- "ragconnect.tests/src/test/02-after-ragconnect"
- "ragconnect.tests/src/test/java-gen"
expire_in: 1 week
test:
......@@ -57,9 +59,9 @@ publish-dev:
- "./gradlew setDevVersionForCI"
- "./gradlew publish"
except:
- master
- main
publish-master:
publish-main:
image: openjdk:11
stage: publish
needs:
......@@ -67,26 +69,26 @@ publish-master:
script:
- "./gradlew publish"
only:
- master
- main
ragdoc_build:
image:
name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-builder"
entrypoint: [""]
stage: ragdoc_build
needs:
- build
script:
- JAVA_FILES=$(find ragconnect.base/src/ -name '*.java')
- echo $JAVA_FILES | wc -l
- /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES
artifacts:
paths:
- "data/"
expire_in: 1 week
ragdoc_view:
image:
name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-view:relations"
entrypoint: [""]
stage: ragdoc_view
needs:
- ragdoc_build
......@@ -95,10 +97,11 @@ ragdoc_view:
- mkdir -p pages/docs/ragdoc
- OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc
- cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR
- /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR
- BASE_HREF=/ragconnect/ragdoc/ /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR
artifacts:
paths:
- "pages/docs/ragdoc"
expire_in: 1 week
build_cloc:
image: "alpine:latest"
......@@ -111,6 +114,7 @@ build_cloc:
artifacts:
paths:
- pages/docs/cloc.md
expire_in: 1 week
.pages-template:
image: python:3.10.0-bullseye
......@@ -128,15 +132,16 @@ pages-dry-run:
extends: .pages-template
except:
- dev
- master
- main
pages:
extends: .pages-template
artifacts:
paths:
- public/
expire_in: 1 week
only:
- master
- main
pages-dev:
extends: .pages-template
......@@ -148,6 +153,7 @@ pages-dev:
- public/
reports:
dotenv: build.env
expire_in: 1 week
only:
- dev
......
# Adding `RagConnect` to your project
If you want to use `RagConnect`, either use the latest [pre-build version](#use-packaged-version) or clone the repository and [build it yourself](#build-from-source).
Either way, a task for [compiling RelAst specifications](#compiling-relast-specifications) has to be specified.
## Use packaged version
......@@ -25,7 +26,7 @@ configurations {
}
dependencies {
ragconnectClasspath group: 'de.tudresden.inf.st', name: 'ragconnect', version: '0.2.3'
ragconnectClasspath group: 'de.tudresden.inf.st', name: 'ragconnect', version: '{{ragconnect_version()}}'
}
```
......@@ -60,11 +61,11 @@ cd ragconnect
ls ragconnect.base/build/libs/
```
This `ragconnect-<version>.jar` can then be copied to your project.
This `ragconnect-{{ragconnect_version()}}.jar` can then be copied to your project.
Please note, that you can safely use `ragconnect.jar` as filename, because the version can always be printed using `java -jar path/to/ragconnect.jar --version`.
```bash
cp ragconnect.base/build/libs/ragconnect-<version>.jar ../your-project/libs/ragconnect.jar
cp ragconnect.base/build/libs/ragconnect-{{ragconnect_version()}}.jar ../your-project/libs/ragconnect.jar
cd ../your-project/
```
......@@ -90,7 +91,7 @@ task ragConnect(type: JavaExec) {
You might need to add another task for [compiling relast specifications](#compiling-relast-specifications).
# Compiling RelAst specifications
## Compiling RelAst specifications
The task to compile `RagConnect` specifications is typically accompanied by a task to invoke the [RelAst compiler](http://relational-rags.eu/) and the [JastAdd gradle plugin](https://plugins.gradle.org/plugin/org.jastadd).
Currently, the parameter `--useJastAddNames` is **required**, and it may cause incompatibilities if not set.
......
# Changelog
## 1.1.0
### Changes
- Added new REST client handler ([#61](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/61))
### Development Changes
- Bugfix: "error: variable handler is already defined" when using multiple protocols [#58](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/58)
- Bugfix: Inherited components of a type can not be chosen as port targets [#59](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/59)
- Update structure and design of documentation pages
## 1.0.0
### Changes
......
......@@ -3,84 +3,49 @@
The compiler is JastAdd-compliant, i.e., it accepts all flags available for JastAdd, though there is no process how to chain pre-processors _yet_.
Additional options are as follows.
| Name | Required (Default) | Description |
|---|---|---|
| `--rootNode` | Yes | Root node in the base grammar. |
| `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `java` (experimental), `mqtt`, `rest`. |
| `--printYaml` | No (false) | Print out YAML instead of generating files. |
| `--verbose` | No (false) | Print more messages while compiling. |
| `--logReads` | No (false) | Enable logging for every received message. |
| `--logWrites` | No (false) | Enable logging for every sent message. |
| `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. |
| `--logTarget` | No (`console`) | Logging target to use, currently available: `console, slf4j`. |
| `--experimental-jastadd-329` | No (false) | Use tracing events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking](using.md#dependency-tracking-automatically-derived). |
| `--incremental` | No (false) | Enables incremental dependency tracking (if `tracing` is also set appropriately). |
| `--tracing[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). |
| `--version` | No (false) | Print version info and exit (reused JastAdd option) |
| `--o` | No (`.`) | Output directory (reused JastAdd option) |
## Table with available options
| Name | Required (Default) | Description |
|------------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `--rootNode` | Yes | Root node in the base grammar. |
| `--protocols` | No (`mqtt`) | Protocols to enable, one of `java` (experimental), `mqtt`, `rest`, see [Handlers][handlers] for details. |
| `--printYaml` | No (false) | Print out YAML instead of generating files. |
| `--verbose` | No (false) | Print more messages while compiling. |
| `--logReads` | No (false) | Enable logging for every received message. |
| `--logWrites` | No (false) | Enable logging for every sent message. |
| `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. |
| `--logTarget` | No (`console`) | Logging target to use, currently available: `console, slf4j`. |
| `--experimental-jastadd-329` | No (false) | Use tracing events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking][automatic-dependency-tracking]. |
| `--incremental` | No (false) | Enables incremental dependency tracking (if `tracing` is also set appropriately). |
| `--tracing[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). |
| `--version` | No (false) | Print version info and exit (reused JastAdd option) |
| `--o` | No (`.`) | Output directory (reused JastAdd option) |
All files to be processed have to be passed as arguments.
Their type is deduced by the file extension (`ast` and `relast` for input grammars, `connect` and `ragconnect` for RagConnect definitions file).
# Additional software dependencies
## Additional software dependencies
Using RagConnect itself does not introduce dependencies.
However, depending on the selected protocols and/or used features, additional dependencies are required when using the generated code.
## Communication protocol characteristics
### Used features
### Java
- Protocol identifier: `java`
- URI scheme: `java://<ignored-host>[:ignored-port]/<topic>`
- the value for host and port are always ignored, but are necessary to form a legal URI
- No required runtime dependencies
- Additional remarks:
- First leading slash not included in topic.
- Currently, the default mappings are applied, which requires a consumer to expect `byte[]` (instead of a more intuitive token or node value). This might change in future versions.
### MQTT
- Protocol identifier: `mqtt`
- URI scheme: `mqtt://<broker-host>[:port]/<topic>`
- Default port: 1883
- Type for mapping definitions: `byte[]`
- Required runtime dependencies:
- `group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'`
- Additional remarks:
- First leading slash not included in topic.
- Mqtt is selected by default, so this dependency therefore is required "by default".
- Might work with other versions of `org.fusesource.mqtt-client.mqtt.client` as well.
### REST
- Protocol identifier: `rest`
- URI scheme: `rest://localhost[:port]/<path>`
- Default port: 4567
- Type for mapping definitions: `String`
- Required runtime dependencies:
- `group: 'com.sparkjava', name: 'spark-core', version: '2.9.3'`
- Additional remarks:
- Host is always `localhost`.
- Might work with newer versions of `com.sparkjava.spark-core` as well.
- For debugging, it is beneficial to include an implementation for [SLF4J][slf4j].
## Used features
### Automatic dependency tracking
#### Automatic dependency tracking
- Condition: When passing `--incremental` and `--tracing=flush` to RagConnect
- Required runtime dependencies: _none_
- Required options for RelAST compiler: _none_
- Required options for JastAdd:
- `--incremental`
- `--tracing=flush`
- `--incremental=param` (enable incremental evaluation)
- `--tracing=flush` (enable tracing of events)
- `--cache=all` (set all attributes to be cached)
- Remarks:
- Other (additional) values passed to those two options must be equal (e.g., `--incremental=param` passed to RagConnect must be also passed to JastAdd)
- Other values besides `flush` can be added to `--tracing`
- [Feature description](using.md#dependency-tracking-automatically-derived)
### (Safer) Automatic dependency tracking
#### (Safer) Automatic dependency tracking
- Condition: When passing `--experimental-jastadd-329` to RagConnect
- Required runtime dependencies: _none_
......@@ -90,7 +55,7 @@ However, depending on the selected protocols and/or used features, additional de
- JastAdd version has to support `INC_FLUSH_START` and `INC_FLUSH_END` (i.e., has [issue #329][jastadd-issue-329] resolved)
- [Feature description](using.md#dependency-tracking-automatically-derived)
### Tree/List Ports
#### Tree/List Ports
- Condition: When using ports along with default mappings for subtrees
- Required runtime dependencies:
......@@ -102,7 +67,7 @@ However, depending on the selected protocols and/or used features, additional de
- Remarks:
- [Feature description](using.md#an-advanced-example)
### Logging Target SLF4J
#### Logging Target SLF4J
- Condition: When passing `--logTarget=slf4j` to RagConnect
- Required runtime dependencies:
......@@ -113,4 +78,5 @@ However, depending on the selected protocols and/or used features, additional de
- Additionally, a slf4j binding is required, see [the slf4j user manual][slf4j]
[jastadd-issue-329]: https://bitbucket.org/jastadd/jastadd2/issues/329/add-event-for-completion-of-flush
[slf4j]: https://www.slf4j.org/manual.html
[automatic-dependency-tracking]: using.md#dependency-tracking-automatically-derived
[handlers]: handlers.md
......@@ -5,9 +5,9 @@ To add a new communication protocol, the following locations have to be changed
### Within `ragconnect.base/src/main/resources`
{% raw %}
- Add a new handler `ABCHandler.jadd`, similar to the existing handlers.
- Add a new handler `ABCHandler.jadd`, similar to the existing handlers. A handler must have a constructor accepting a single String parameter, and must have a `close()` method cleaning up any held resources.
- In `handler.mustache`, add further methods if needed for handler usage in the application code (similar to `{{rootNodeName}}.{{SetupWaitUntilReadyMethodName}}` for `mqtt`)
- In `receiveDefinition.mustache` and `sendDefinition.mustache`: add a new case in the switch statements defining the logic to happen upon connect and disconnect for both definitions. If the new protocol is close to a PUSH semantic, follow `mqtt`. If it is closer to PULL semantic, follow `rest`.
- In `receiveDefinition.mustache` and `sendDefinition.mustache`: add a new case in the switch statements defining the logic to happen upon connect and disconnect for both definitions (that are four distinct locations). If the new protocol is close to a PUSH semantic, follow `mqtt`. If it is closer to PULL semantic, follow `restClient`.
{% endraw %}
### Within `ragconnect.base/src/main/jastadd`
......@@ -18,7 +18,7 @@ In `Handlers.jrag`: Add a new attribute `RagConnect.abcHandler()` returning the
In `Compiler.java`:
- Add a new choice for `--protocols` similar to the existing ones
- Add a newly constructed handler in `setConfiguration` with the needed fields (definition file name within `resources` directory, commonly `ABCHandler.jadd`; class name of the handler; unique name for the protocol; whether the handler is used, i.e., if it was given in `--protocols`)
- Add a newly constructed handler in `setConfiguration` with the needed fields (class name of the handler; unique name for the protocol (must be a valid Java identifier); whether the handler is used, i.e., if it was given in `--protocols`)
Furthermore, new test cases are appreciated, see [below](#writing-tests).
......
# Communication Protocol Characteristics (Handlers)
## Java (experimental)
Uses Java methods to supply values (receive) and for callbacks (send).
- Protocol identifier: `java`
- URI scheme: `java://<ignored-host>[:ignored-port]/<topic>`
- the value for host and port are always ignored, but are necessary to form a legal URI
- No required runtime dependencies
- Receive behaviour: Use the generated method `ragconnectJavaPush` to pass a value to the receiving port.
- Send behaviour: When the value to be sent changes, previously registered callbacks are invoked.
- Additional remarks:
- First leading slash not included in topic.
- Currently, the default mappings are applied, which requires a consumer to expect `byte[]` (instead of a more intuitive token or node value). This might change in future versions.
## MQTT
Use an MQTT broker to receive and send messages.
- Protocol identifier: `mqtt`
- URI scheme: `mqtt://<broker-host>[:port]/<topic>`
- Default port: 1883
- Type for mapping definitions: `byte[]`
- Required runtime dependencies:
- `group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'`
- Receive behaviour: Upon connection, instruct the MQTT broker to listen for messages on some topic and pass the value of those messages to the receiving port.
- Send behaviour: When the value to be sent changes, publish a message to the topic specified upon connection.
- Additional remarks:
- First leading slash not included in topic.
- Mqtt is selected by default, so this dependency therefore is required "by default".
- Might work with other versions of `org.fusesource.mqtt-client.mqtt.client` as well.
## REST Server
Create a new REST server with its own target routes.
- Protocol identifier: `rest`
- URI scheme: `rest://localhost[:port]/<path>`
- Default port: 4567
- Type for mapping definitions: `byte[]`
- Required runtime dependencies:
- `group: 'com.sparkjava', name: 'spark-core', version: '2.9.3'`
- Receive behaviour: Upon connection, create a new PUT connection and pass the value of every call to this PUT route to the receiving port.
- Send behaviour: Upon connection, create a new GET connection and serve the latest value at this GET route.
- Additional remarks:
- Host is always `localhost`.
- Targets to be invoked need to replace `rest` with `http`
- Might work with newer versions of `com.sparkjava.spark-core` as well.
- For debugging, it is beneficial to include an implementation for [SLF4J][slf4j].
## REST Client
Invoke REST routes to fetch and send values.
- Protocol identifier: `restClient`
- URI scheme: `restClient://localhost[:port]/<path>`
- Default port: 80
- Type for mapping definitions: `byte[]`
- No required runtime dependencies
- Receive behaviour: Whenever the accessor is called, a GET request fetches the latest data and returns this data.
- Send behaviour: When the value to be sent changes, a PUT request sends this data.
- Additional remarks:
- Invoked target replaces `restClient` with `http`
- **Important constraint**: Receiving ports are only supported for tokens, since they interrupt the getter method!
[slf4j]: https://www.slf4j.org/manual.html
pages/docs/img/2022_acsos/architecture.png

96.1 KiB

File added
File added
pages/docs/img/ST-black.png

18.2 KiB

......@@ -20,11 +20,11 @@ The other main aspect (which is currently not really used) is `IntermediateToYAM
This is used to generate a YAML file containing the data used by mustache.
It can be used by the default mustache implementation together with the templates.
# Implementation Details
## Implementation Details
In the following, details for special implementation topics are discussed.
## Forwarding
### Forwarding
When a nonterminal is used in a send ports, it needs an implicit forwarding attribute to work, because only _computed elements_ can be sent.
Since the nonterminal itself should be sent, the generated attribute simply returns this nonterminal.
......@@ -34,9 +34,9 @@ This way, the dependency tracking registers a dependency between structure and t
The attribute (as well as any other generated element) is prefixed with `_ragconnect_` to avoid potential name conflicts with user-specified elements.
# Implementation Hints
## Implementation Hints
## Debugging Tests and Finding Bugs
### Debugging Tests and Finding Bugs
To help with finding errors/bugs when tests fail, there are several things to find the correct spot.
......
# Use cases with `RagConnect`
## MODELS Paper (2022) - Codename 'Ros3Rag'
In the paper [*"Incremental Causal Connection for Self-Adaptive Systems Based on Relational Reference Attribute Grammars"*](https://doi.org/10.1145/3550355.3552460), a [previous use case](#mpm4cps-paper-2020-codename-ros2rag) was extended to Collaborative, Teaching-Based Robotic Cells.
![Screenshot](img/2022_models/photo.jpg)
This paper was presented on October, 26th 2022 in the technical track of the [MODELS 2022 conference](https://conf.researchr.org/home/models-2022) (Oct 23 - Oct 29).
There is an [artifact hosted at Zenodo](https://doi.org/10.5281/zenodo.7009758) containing all source code and the executable case study.
For more information, see the [presented slides](img/2022_models/slides.pdf) or the accompanied [poster](img/2022_models/poster.pdf).
The repository with the used source code can be found at: <https://git-st.inf.tu-dresden.de/ceti/ros/models2022>
## ACSOS Paper (2022) - Codename 'Motion Grammar Demo'
In the paper [*"Specifying Reactive Robotic Applications
With Reference Attribute Motion Grammars"*](http://mg.relational-rags.eu), motion grammars (an older approach by [Dantham and Stilman](https://doi.org/10.1109/TRO.2013.2239553)) were implemented using Relational RAGs.
![Used Architecture](img/2022_acsos/architecture.png)
This paper was presented on September, 21st 2022 during the [Posters and Demos session](https://2022.acsos.org/track/acsos-2022-posters-and-demos) of the [ACSOS 2022 conference](https://2022.acsos.org/).
For more information, see <http://mg.relational-rags.eu/>.
## MPM4CPS Paper (2020) - Codename 'Ros2Rag'
In the publication [*"Connecting conceptual models using Relational Reference Attribute Grammars"*](https://doi.org/10.1145/3417990.3421437), a use case involving a simulated robot arm and two different models connected to it was shown.
......@@ -28,22 +50,3 @@ docker-compose up rag_app
# Terminal 3: Goal-Model
docker-compose up rag_goal
```
## ACSOS Paper (2022) - Codename 'Motion Grammar Demo'
In the paper [*"Specifying Reactive Robotic Applications
With Reference Attribute Motion Grammars"*](http://mg.relational-rags.eu), motion grammars (an older approach by [Dantham and Stilman](https://doi.org/10.1109/TRO.2013.2239553)) were implemented using Relational RAGs.
This paper will be presented on September, 21st 2022 during the [Posters and Demos session](https://2022.acsos.org/track/acsos-2022-posters-and-demos) of the [ACSOS 2022 conference](https://2022.acsos.org/).
For more information, see <http://mg.relational-rags.eu/>.
## MODELS Paper (2022) - Codename 'Ros3Rag'
In the paper [*"Incremental Causal Connection for Self-Adaptive Systems Based on Relational Reference Attribute Grammars"*](https://doi.org/10.1145/3550355.3552460), a [previous use case](#mpm4cps-paper-codename-ros2rag) was extended to Collaborative, Teaching-Based Robotic Cells.
![Screenshot](img/2022_models/photo.jpg)
This paper will be presented in the technical track of the [MODELS 2022 conference](https://conf.researchr.org/home/models-2022) (Oct 23 - Oct 29).
There is an [artifact hosted at Zenodo](https://doi.org/10.5281/zenodo.7009758) containing all source code and the executable case study.
Furthermore, the presentation slides and a poster will be available soon.
The repository with the used source code can be found at: <https://git-st.inf.tu-dresden.de/ceti/ros/models2022>
......@@ -4,7 +4,7 @@ The full example is available at <https://git-st.inf.tu-dresden.de/jastadd/ragco
## Preparation and Specification
The following examples are inspired by real [test cases](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/tree/master/ragconnect.tests/src/test/01-input) read1write2 and tokenValueSend.
The following examples are inspired by real [test cases](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/tree/main/ragconnect.tests/src/test/01-input) read1write2 and tokenValueSend.
The idea is to have two non-terminals, where input information is received on one of them, and - after transformation - is sent out by both.
Let's use the following grammar:
......@@ -127,11 +127,11 @@ Round maps float f to int {:
... connecting first could mean to store the first rounded value and not propagating this update, since no dependencies are set, and not propagating further updates leading to the same rounded value even after setting the dependencies.
# An advanced example
## An advanced example
Non-terminal children can also be selected as ports (not only tokens).
## Normal Non-Terminal Children
### Normal Non-Terminal Children
Receiving normal non-terminal children and optionals means to replace them with a new node deserialized from the received message.
Sending them involves serializing a node, and sending this representation in a message.
......@@ -158,7 +158,7 @@ To process non-terminals, default mappings are provided for every non-terminal t
They use the JSON serialization offered by the RelAST compiler, i.e., interpret the message as a `String`, deserialize the content reading the message as JSON, or vice versa.
Additional dependencies are required to use this feature, as detailed in [the compiler section](compiler.md#treelist-ports).
## Receiving List Children
### Receiving List Children
When receiving list children, there are a few more options to match the connection to given requirements.
......@@ -171,7 +171,7 @@ ReceiverRoot ::= A* ;
Several options are possible (please also refer to the specification of the [connect DSL](dsl.md):
### (empty)
#### (empty)
A message for a list port can be interpreted as a complete list (a sequence of nodes of type `A`) by not specifying any special keyword:
......@@ -179,7 +179,7 @@ A message for a list port can be interpreted as a complete list (a sequence of n
receive ReceiverRoot.A ;
```
### with add
#### with add
Upon receiving the message, the deserialized list can also be appended to the existing list instead of replace the latter.
This can be achieved using the keyword `with add` :
......@@ -188,7 +188,7 @@ This can be achieved using the keyword `with add` :
receive with add ReceiverRoot.Alfa ;
```
### indexed
#### indexed
A message for a list port can also be interpreted as an element of this list.
......@@ -203,7 +203,7 @@ The list must have enough elements once a message is received.
receiverRoot.connectA("<some-url>", 1);
```
### indexed (wildcard)
#### indexed (wildcard)
Similar to the `indexed` case above, messages are interpreted as an element of the list, but the connection can also be made using a "wildcard topic" and without an index.
Then, once a message is received from a new concrete topic, the deserialized element will be appended to the list and this topic is associated with the index of the newly added element.
......@@ -223,7 +223,7 @@ assertEquals(receiverRoot.getAList(), list("1", "other"));
assertEquals(receiverRoot.getAList(), list("new", "other"));
```
### indexed + with add
#### indexed + with add
Combining `indexed` and `with add` results in a connection, where messages are interpreted as elements of the list, and new elements are appended to the existing list.
In that case, wildcard and non-wildcard connections behave in the same way, as no index has to be passed, and the element is always append at the end.
......@@ -245,7 +245,7 @@ assertEquals(receiverRoot.getAList(), list("1", "other"));
assertEquals(receiverRoot.getAList(), list("1", "other", "new"));
```
## Using attributes as port targets
### Using attributes as port targets
As described in the [DSL specification](dsl.md), attributes can be used as port targets.
They can only be used in send ports, and the return type of the attribute must be specified in the connect specification (because aspect files are not handled completely yet).
......
......@@ -7,6 +7,7 @@ nav:
- "Using RagConnect (by Example)": using.md
- "RagConnect Specification Language": dsl.md
- "Compiler options": compiler.md
- "Communication Protocols": handlers.md
- "Use Cases": use_cases.md
- "Inner workings": inner-workings.md
- "Evaluation Metrics: Lines of Code": cloc.md
......@@ -15,12 +16,26 @@ nav:
- "API documentation": ragdoc/index.html
theme:
name: readthedocs
custom_dir: custom_theme/
name: material
font: false
palette:
# Palette toggle for light mode
- scheme: default
toggle:
icon: material/brightness-7
name: Switch to dark mode
# Palette toggle for dark mode
- scheme: slate
toggle:
icon: material/brightness-4
name: Switch to light mode
favicon: img/ST-black.png
icon:
logo: material/connection
markdown_extensions:
- toc:
permalink:
permalink: true
- admonition
plugins:
......
mkdocs==1.2.2
mkdocs-git-revision-date-localized-plugin==0.10.3
mkdocs-macros-plugin==0.6.3
mike==1.1.2
Jinja2==2.11.2
MarkupSafe==1.1.1
mkdocs==1.4.2
mkdocs-git-revision-date-localized-plugin==1.1.0
mkdocs-macros-plugin==0.7.0
mkdocs-material==8.5.10
mkdocs-material-extensions==1.1
Jinja2==3.1.2
MarkupSafe==2.1.1
......@@ -249,7 +249,7 @@ task newVersion() {
task setDevVersionForCI() {
doFirst {
def props = new Properties()
props['version'] = version + "-$System.env.CI_PIPELINE_IID"
props['version'] = version + "-dev-$System.env.CI_PIPELINE_IID"
props.store(file(versionFile).newWriter(), null)
}
}
......
......@@ -98,10 +98,22 @@ aspect Analysis {
eq ContextFreeTypePortTarget.hasAttributeResetMethod() = false;
// --- needProxyToken ---
syn boolean TokenComponent.needProxyToken() = !getDependencySourceDefinitionList().isEmpty() ||
getTokenPortTargetList().stream()
.map(PortTarget::containingPortDefinition)
.anyMatch(PortDefinition::shouldNotResetValue);
syn boolean TokenComponent.needProxyToken() {
for (Component comp : meOwnedByOthers()) {
TokenComponent tokenComp = comp.asTokenComponent();
if (tokenComp.directNeedProxyToken()) {
return true;
}
}
return directNeedProxyToken();
}
syn boolean TokenComponent.directNeedProxyToken() {
return !getDependencySourceDefinitionList().isEmpty() ||
getTokenPortTargetList().stream()
.map(PortTarget::containingPortDefinition)
.anyMatch(def -> def.shouldNotResetValue() || ragconnect().restClientHandler().getInUse());
}
// --- effectiveUsedAt ---
coll Set<PortDefinition> MappingDefinition.effectiveUsedAt()
......
......@@ -2,6 +2,7 @@ aspect RagConnectHandlers {
syn Handler RagConnect.javaHandler() = resolveHandlerByName("java");
syn Handler RagConnect.mqttHandler() = resolveHandlerByName("mqtt");
syn Handler RagConnect.restHandler() = resolveHandlerByName("rest");
syn Handler RagConnect.restClientHandler() = resolveHandlerByName("restClient");
private Handler RagConnect.resolveHandlerByName(String uniqueName) {
for (Handler handler : getHandlerList()) {
......
......@@ -232,7 +232,8 @@ aspect MustacheMappingApplicationAndDefinition {
eq MRelationSendDefinition.preemptiveReturn() = "return false;";
eq MTokenReceiveDefinition.firstInputVarName() = "message";
eq MTokenReceiveDefinition.preemptiveExpectedValue() = getterMethodCall();
// if receiverName variable is set, use internal getter instead to avoid StackOverflow
eq MTokenReceiveDefinition.preemptiveExpectedValue() = "(" + getPortDefinition().receiverName() + " != null ? get" + getPortDefinition().token().internalName() + "() : " + getterMethodCall() + ")";
eq MTokenReceiveDefinition.preemptiveReturn() = "return;";
eq MTokenSendDefinition.firstInputVarName() = getterMethodCall();
......@@ -358,7 +359,14 @@ aspect MustacheRagConnect {
eq ContextFreeTypePortTarget.impliedPortDefinitions() {
JastAddList<PortDefinition> result = super.impliedPortDefinitions();
PortDefinition containingDef = containingPortDefinition();
Set<TypeComponent> seenTypeComponents = new HashSet<>();
for (TypeComponent typeComponent : getTypeDecl().occurencesInProductionRules()) {
// only process each once
if (seenTypeComponents.contains(typeComponent)) {
continue;
}
seenTypeComponents.add(typeComponent);
List<PortDefinition> defsForTypeComponent = lookupGivenTypePortDefinitions(typeComponent);
if (!defsForTypeComponent.stream().anyMatch(containingDef::matchesType)) {
// there is no user-defined port definition for this typeComponent yet
......@@ -398,7 +406,7 @@ aspect MustacheReceiveAndSendAndHandleUri {
syn String PortDefinition.connectParameterName() = "uriString";
syn String PortDefinition.disconnectMethodName() {
// if both (send and receive) are defined for an port, ensure methods with different names
// if both (send and receive) are defined for a port, ensure methods with different names
String extra;
if (getPortTarget().isTokenPortTarget()) {
extra = lookupTokenPortDefinitions(token()).size() > 1 ? uniqueSuffix() : "";
......@@ -518,6 +526,7 @@ aspect MustacheSendDefinition {
syn boolean PortDefinition.relationPortWithListRole() = getPortTarget().relationPortWithListRole();
syn String PortDefinition.receiverName() = getPortTarget().receiverName();
syn String PortDefinition.senderName() = getPortTarget().senderName();
syn java.util.List<SendIncrementalObserverEntry> PortDefinition.sendIncrementalObserverEntries() {
......@@ -576,6 +585,9 @@ containingPortDefinition().getIndexBasedListAccess());
syn boolean PortTarget.relationPortWithListRole() = false;
eq RelationPortTarget.relationPortWithListRole() = getRole().isListRole();
syn String PortTarget.receiverName() = ragconnect().internalRagConnectPrefix() + "_receiver_" + entityName();
eq ContextFreeTypePortTarget.receiverName() = null;
syn String PortTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + entityName();
eq ContextFreeTypePortTarget.senderName() = null;
......@@ -625,17 +637,37 @@ containingPortDefinition().getIndexBasedListAccess());
aspect MustacheTokenComponent {
// === TokenComponent ===
syn java.util.List<DependencyDefinition> TokenComponent.dependencySourceDefinitionsOwnedByMe() {
java.util.List<DependencyDefinition> result = new java.util.ArrayList<>();
result.addAll(getDependencySourceDefinitions());
for (Component comp : meOwnedByOthers()) {
result.addAll(comp.asTokenComponent().getDependencySourceDefinitions());
}
return result;
}
syn String TokenComponent.internalName() = needProxyToken() ? ragconnect().internalRagConnectPrefix() + getName() : getName();
syn String TokenComponent.javaType() = effectiveJavaTypeUse().prettyPrint();
syn PortDefinition TokenComponent.normalTokenReceiveDef() {
for (Component comp : meOwnedByOthers()) {
PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenReceiveDef();
if (maybeResult != null) {
return maybeResult;
}
}
return directNormalTokenReceiveDef();
}
syn PortDefinition TokenComponent.normalTokenSendDef() {
for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) {
return target.containingPortDefinition();
for (Component comp : meOwnedByOthers()) {
PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenSendDef();
if (maybeResult != null) {
return maybeResult;
}
}
return null;
return directNormalTokenSendDef();
}
syn String TokenComponent.parentTypeName() = containingTypeDecl().getName();
......@@ -663,6 +695,26 @@ aspect MustacheTokenComponent {
}
// > see MustacheSend for updateMethodName, writeMethodName
// === attributes needed for computing above ones ===
syn PortDefinition TokenComponent.directNormalTokenReceiveDef() {
for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && !target.containingPortDefinition().getSend() &&
ragconnect().restClientHandler().getInUse()) {
return target.containingPortDefinition();
}
}
return null;
}
syn PortDefinition TokenComponent.directNormalTokenSendDef() {
for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) {
return target.containingPortDefinition();
}
}
return null;
}
}
aspect MustacheTypeDecl {
......@@ -670,6 +722,10 @@ aspect MustacheTypeDecl {
syn String TypeComponent.parentTypeName() = containingTypeDecl().getName();
syn String TypeComponent.disconnectMethodName() {
List<TypePortTarget> typePortTargets = getTypePortTargets();
while (typePortTargets.isEmpty() && getRealComponent() != null) {
// get for "real" typeComponent (of super-type) and use its getTypePortTargets
typePortTargets = getRealComponent().asTypeComponent().getTypePortTargets();
}
if (typePortTargets.isEmpty()) {
return "MISSING_PORT";
} else {
......@@ -681,7 +737,7 @@ aspect MustacheTypeDecl {
syn List<TypeComponent> TypeDecl.occurencesInProductionRules() {
List<TypeComponent> result = new ArrayList<>();
for (TypeDecl typeDecl : program().typeDecls()) {
for (Component comp : typeDecl.getComponentList()) {
for (Component comp : typeDecl.allComponentsAsOwnedByMe()) {
if (comp.isTypeComponent() && comp.asTypeComponent().getTypeDecl().equals(this)) {
result.add(comp.asTypeComponent());
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment