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

WIP: restClient receiving for tokens.

- added simple client-server test for tokens. TODO check for nonterminal
- no close needed
- added disconnect
- changed rest-server to use byte[] instead of String for messages
- use dedicated documentation page for handlers
- TODO: merge RestClientServerHandler and RestClientHandler
parent e44eb189
No related branches found
No related tags found
1 merge request!38Resolve "New Handler: REST client"
Showing
with 291 additions and 94 deletions
...@@ -6,16 +6,16 @@ Additional options are as follows. ...@@ -6,16 +6,16 @@ Additional options are as follows.
## Table with available options ## Table with available options
| Name | Required (Default) | Description | | Name | Required (Default) | Description |
|---|---|---| |------------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `--rootNode` | Yes | Root node in the base grammar. | | `--rootNode` | Yes | Root node in the base grammar. |
| `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `java` (experimental), `mqtt`, `rest`. | | `--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. | | `--printYaml` | No (false) | Print out YAML instead of generating files. |
| `--verbose` | No (false) | Print more messages while compiling. | | `--verbose` | No (false) | Print more messages while compiling. |
| `--logReads` | No (false) | Enable logging for every received message. | | `--logReads` | No (false) | Enable logging for every received message. |
| `--logWrites` | No (false) | Enable logging for every sent message. | | `--logWrites` | No (false) | Enable logging for every sent message. |
| `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. | | `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. |
| `--logTarget` | No (`console`) | Logging target to use, currently available: `console, slf4j`. | | `--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). | | `--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). | | `--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). | | `--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) | | `--version` | No (false) | Print version info and exit (reused JastAdd option) |
...@@ -29,44 +29,6 @@ Their type is deduced by the file extension (`ast` and `relast` for input gramma ...@@ -29,44 +29,6 @@ Their type is deduced by the file extension (`ast` and `relast` for input gramma
Using RagConnect itself does not introduce 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. However, depending on the selected protocols and/or used features, additional dependencies are required when using the generated code.
### Communication protocol characteristics
#### 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 ### Used features
#### Automatic dependency tracking #### Automatic dependency tracking
...@@ -116,4 +78,5 @@ However, depending on the selected protocols and/or used features, additional de ...@@ -116,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] - 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 [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
# 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: `String` --> TODO --> `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`.
- 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`
[slf4j]: https://www.slf4j.org/manual.html
...@@ -7,6 +7,7 @@ nav: ...@@ -7,6 +7,7 @@ nav:
- "Using RagConnect (by Example)": using.md - "Using RagConnect (by Example)": using.md
- "RagConnect Specification Language": dsl.md - "RagConnect Specification Language": dsl.md
- "Compiler options": compiler.md - "Compiler options": compiler.md
- "Communication Protocols": handlers.md
- "Use Cases": use_cases.md - "Use Cases": use_cases.md
- "Inner workings": inner-workings.md - "Inner workings": inner-workings.md
- "Evaluation Metrics: Lines of Code": cloc.md - "Evaluation Metrics: Lines of Code": cloc.md
......
...@@ -2,7 +2,7 @@ aspect RagConnectHandlers { ...@@ -2,7 +2,7 @@ aspect RagConnectHandlers {
syn Handler RagConnect.javaHandler() = resolveHandlerByName("java"); syn Handler RagConnect.javaHandler() = resolveHandlerByName("java");
syn Handler RagConnect.mqttHandler() = resolveHandlerByName("mqtt"); syn Handler RagConnect.mqttHandler() = resolveHandlerByName("mqtt");
syn Handler RagConnect.restHandler() = resolveHandlerByName("rest"); syn Handler RagConnect.restHandler() = resolveHandlerByName("rest");
syn Handler RagConnect.restClientHandler() = resolveHandlerByName("rest_client"); syn Handler RagConnect.restClientHandler() = resolveHandlerByName("restClient");
private Handler RagConnect.resolveHandlerByName(String uniqueName) { private Handler RagConnect.resolveHandlerByName(String uniqueName) {
for (Handler handler : getHandlerList()) { for (Handler handler : getHandlerList()) {
......
...@@ -699,7 +699,8 @@ aspect MustacheTokenComponent { ...@@ -699,7 +699,8 @@ aspect MustacheTokenComponent {
// === attributes needed for computing above ones === // === attributes needed for computing above ones ===
syn PortDefinition TokenComponent.directNormalTokenReceiveDef() { syn PortDefinition TokenComponent.directNormalTokenReceiveDef() {
for (PortTarget target : getTokenPortTargetList()) { for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && ragconnect().restClientHandler().getInUse()) { if (target.isTokenPortTarget() && !target.containingPortDefinition().getSend() &&
ragconnect().restClientHandler().getInUse()) {
return target.containingPortDefinition(); return target.containingPortDefinition();
} }
} }
......
...@@ -233,6 +233,15 @@ aspect IntermediateToYAML { ...@@ -233,6 +233,15 @@ aspect IntermediateToYAML {
} }
return sb; return sb;
} }
// FIXME: remove refine once fixed in upstream mustache
refine Helpers protected SimpleElement ComplexElement.makeStringElement(String value) {
// simple test, check for special characters
return containsAny(value, ":#,[{\"\n") ?
StringElement.of(value.replace("\n", "\\n").replace("\"", "\\\"")) :
ValueElement.of(value);
}
} }
aspect Navigation { aspect Navigation {
......
...@@ -39,7 +39,7 @@ public class Compiler extends AbstractCompiler { ...@@ -39,7 +39,7 @@ public class Compiler extends AbstractCompiler {
private static final String OPTION_PROTOCOL_JAVA = "java"; private static final String OPTION_PROTOCOL_JAVA = "java";
private static final String OPTION_PROTOCOL_MQTT = "mqtt"; private static final String OPTION_PROTOCOL_MQTT = "mqtt";
private static final String OPTION_PROTOCOL_REST = "rest"; private static final String OPTION_PROTOCOL_REST = "rest";
private static final String OPTION_PROTOCOL_REST_CLIENT = "rest-client"; private static final String OPTION_PROTOCOL_REST_CLIENT = "restClient";
public Compiler() { public Compiler() {
super("ragconnect", true); super("ragconnect", true);
...@@ -343,7 +343,7 @@ public class Compiler extends AbstractCompiler { ...@@ -343,7 +343,7 @@ public class Compiler extends AbstractCompiler {
ragConnect.addHandler(new Handler("JavaHandler", "java", optionProtocols.hasValue(OPTION_PROTOCOL_JAVA))); ragConnect.addHandler(new Handler("JavaHandler", "java", optionProtocols.hasValue(OPTION_PROTOCOL_JAVA)));
ragConnect.addHandler(new Handler("MqttServerHandler", "mqtt", optionProtocols.hasValue(OPTION_PROTOCOL_MQTT))); ragConnect.addHandler(new Handler("MqttServerHandler", "mqtt", optionProtocols.hasValue(OPTION_PROTOCOL_MQTT)));
ragConnect.addHandler(new Handler("RestServerHandler", "rest", optionProtocols.hasValue(OPTION_PROTOCOL_REST))); ragConnect.addHandler(new Handler("RestServerHandler", "rest", optionProtocols.hasValue(OPTION_PROTOCOL_REST)));
ragConnect.addHandler(new Handler("RestClientServerHandler", "rest_client", ragConnect.addHandler(new Handler("RestClientServerHandler", "restClient",
optionProtocols.hasValue(OPTION_PROTOCOL_REST_CLIENT))); optionProtocols.hasValue(OPTION_PROTOCOL_REST_CLIENT)));
} }
......
// dispatch depending on URI. might not be necessary // dispatch depending on URI. might not be necessary
public class RestClientServerHandler { public class RestClientServerHandler {
public RestClientServerHandler(String name) { public RestClientServerHandler(String name) {
// TODO implement // empty
} }
RestClientHandler singleton = new RestClientHandler(); RestClientHandler singleton = new RestClientHandler();
...@@ -10,23 +10,42 @@ public class RestClientServerHandler { ...@@ -10,23 +10,42 @@ public class RestClientServerHandler {
return singleton.newReceiverFor(connectToken, callback); return singleton.newReceiverFor(connectToken, callback);
} }
public boolean disconnect(RagConnectToken connectToken) { public RestClientPreparedRequest preparePut(java.net.URI uri) {
// TODO implement return singleton.preparePut(uri);
return false; }
void sendRequestAsync(RestClientPreparedRequest preparedRequest, byte[] message) {
singleton.sendRequestAsync(preparedRequest, message);
} }
public void close() { public void close() {
// TODO implement // empty
}
}
public class RestClientPreparedRequest {
java.net.http.HttpRequest.Builder builder;
RestClientPreparedRequest(java.net.http.HttpRequest.Builder builder) {
this.builder = builder;
} }
} }
public class RestClientHandler { public class RestClientHandler {
private java.net.http.HttpClient httpClient;
RestClientHandler() {
httpClient = java.net.http.HttpClient.newHttpClient();
}
public RagConnectReceiver newReceiverFor(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) { public RagConnectReceiver newReceiverFor(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) {
java.net.URI target = java.net.URI.create(connectToken.uri.toString().replaceFirst("restClient", "http")); java.net.URI target = java.net.URI.create(connectToken.uri.toString().replaceFirst("restClient", "http"));
java.net.http.HttpRequest httpRequest = java.net.http.HttpRequest.newBuilder(target)
.GET()
.build();
return () -> { return () -> {
byte[] rawInput; byte[] rawInput;
try { try {
rawInput = fetchFrom(target); rawInput = fetchFrom(httpRequest);
} catch (Exception e) { } catch (Exception e) {
{{logException}}("Exception when fetching from " + target, e); {{logException}}("Exception when fetching from " + target, e);
return; return;
...@@ -35,15 +54,34 @@ public class RestClientHandler { ...@@ -35,15 +54,34 @@ public class RestClientHandler {
}; };
} }
byte[] fetchFrom(java.net.URI uri) throws java.io.IOException, InterruptedException { byte[] fetchFrom(java.net.http.HttpRequest httpRequest) throws java.io.IOException, InterruptedException {
// TODO the request should only be built once, and not every time the GET call is run return httpClient.send(httpRequest, java.net.http.HttpResponse.BodyHandlers.ofByteArray()).body();
java.net.http.HttpRequest httpRequest = java.net.http.HttpRequest.newBuilder() }
.uri(uri)
.GET() RestClientPreparedRequest preparePut(java.net.URI uri) {
java.net.URI target = java.net.URI.create(uri.toString().replaceFirst("restClient", "http"));
java.net.http.HttpRequest.Builder httpRequestBuilder = java.net.http.HttpRequest.newBuilder(target);
return new RestClientPreparedRequest(httpRequestBuilder);
}
void sendRequestSync(RestClientPreparedRequest preparedRequest, byte[] message) {
java.net.http.HttpRequest httpRequest = preparedRequest.builder
.PUT(java.net.http.HttpRequest.BodyPublishers.ofByteArray(message))
.build(); .build();
java.net.http.HttpClient httpClient = java.net.http.HttpClient.newHttpClient(); httpClient.sendAsync(httpRequest, java.net.http.HttpResponse.BodyHandlers.discarding());
java.net.http.HttpResponse<byte[]> response = httpClient.send(httpRequest, }
java.net.http.HttpResponse.BodyHandlers.ofByteArray());
return response.body(); void sendRequestAsync(RestClientPreparedRequest preparedRequest, byte[] message) {
java.net.http.HttpRequest httpRequest = preparedRequest.builder
.PUT(java.net.http.HttpRequest.BodyPublishers.ofByteArray(message))
.build();
java.net.http.HttpResponse response;
try {
response = httpClient.send(httpRequest, java.net.http.HttpResponse.BodyHandlers.ofString());
{{logDebug}}("Response for message to {{log_}} is {{log_}} {{log_}}",
httpRequest, response.statusCode(), response.body());
} catch (java.io.IOException | InterruptedException e) {
{{logException}}("Exception while sending {{log_}}: {{log_}}", httpRequest, e);
}
} }
} }
...@@ -20,13 +20,13 @@ public class RestServerHandler { ...@@ -20,13 +20,13 @@ public class RestServerHandler {
return handler; return handler;
} }
public boolean newPUTConnection(RagConnectToken connectToken, java.util.function.Consumer<String> callback) { public boolean newPUTConnection(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> consumer) {
tokensForRemoval.put(connectToken, callback); tokensForRemoval.put(connectToken, consumer);
resolveHandler(connectToken.uri).newPUTConnection(connectToken.uri.getPath(), callback); resolveHandler(connectToken.uri).newPUTConnection(connectToken.uri.getPath(), consumer);
return true; return true;
} }
public boolean newGETConnection(RagConnectToken connectToken, SupplierWithException<String> supplier) { public boolean newGETConnection(RagConnectToken connectToken, SupplierWithException<byte[]> supplier) {
tokensForRemoval.put(connectToken, supplier); tokensForRemoval.put(connectToken, supplier);
resolveHandler(connectToken.uri).newGETConnection(connectToken.uri.getPath(), supplier); resolveHandler(connectToken.uri).newGETConnection(connectToken.uri.getPath(), supplier);
return true; return true;
...@@ -52,8 +52,8 @@ public class RestHandler { ...@@ -52,8 +52,8 @@ public class RestHandler {
private int port; private int port;
/** Dispatch knowledge */ /** Dispatch knowledge */
private final java.util.Map<String, java.util.List<java.util.function.Consumer<String>>> callbacks; private final java.util.Map<String, java.util.List<java.util.function.BiConsumer<String, byte[]>>> callbacks;
private final java.util.Map<String, SupplierWithException<String>> suppliers; private final java.util.Map<String, SupplierWithException<byte[]>> suppliers;
public RestHandler() { public RestHandler() {
this.port = DEFAULT_PORT; this.port = DEFAULT_PORT;
...@@ -64,23 +64,24 @@ public class RestHandler { ...@@ -64,23 +64,24 @@ public class RestHandler {
public RestHandler setPort(int port) { public RestHandler setPort(int port) {
this.port = port; this.port = port;
start(); start();
spark.Spark.path("", () -> spark.Spark.before((request, response) -> {{logDebug}}("Request on {{log_}}: {{log_}}", request.pathInfo(), request.bodyAsBytes())));
return this; return this;
} }
public void newPUTConnection(String path, java.util.function.Consumer<String> callback) { public void newPUTConnection(String path, java.util.function.BiConsumer<String, byte[]> callback) {
if (callbacks.containsKey(path)) { if (callbacks.containsKey(path)) {
callbacks.get(path).add(callback); callbacks.get(path).add(callback);
} else { } else {
// setup path // setup path
java.util.List<java.util.function.Consumer<String>> callbackList = new java.util.ArrayList<>(); java.util.List<java.util.function.BiConsumer<String, byte[]>> callbackList = new java.util.ArrayList<>();
callbackList.add(callback); callbackList.add(callback);
callbacks.put(path, callbackList); callbacks.put(path, callbackList);
spark.Spark.put(path, (request, response) -> { spark.Spark.put(path, (request, response) -> {
String content = request.body(); byte[] content = request.bodyAsBytes();
java.util.Set<String> errors = new java.util.HashSet<>(); java.util.Set<String> errors = new java.util.HashSet<>();
for (java.util.function.Consumer<String> f : callbackList) { for (java.util.function.BiConsumer<String, byte[]> f : callbackList) {
try { try {
f.accept(content); f.accept(path, content);
} catch (Exception e) { } catch (Exception e) {
errors.add(e.getMessage()); errors.add(e.getMessage());
} }
...@@ -94,7 +95,7 @@ public class RestHandler { ...@@ -94,7 +95,7 @@ public class RestHandler {
} }
} }
public void newGETConnection(String path, SupplierWithException<String> supplier) { public void newGETConnection(String path, SupplierWithException<byte[]> supplier) {
if (suppliers.get(path) != null) { if (suppliers.get(path) != null) {
{{logWarn}}("Overriding existing supplier for '{{log_}}'", path); {{logWarn}}("Overriding existing supplier for '{{log_}}'", path);
} }
......
...@@ -118,10 +118,7 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec ...@@ -118,10 +118,7 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec
{{#restHandler}} {{#restHandler}}
{{#InUse}} {{#InUse}}
case "rest": case "rest":
success = {{attributeName}}().newPUTConnection(connectToken, input -> { success = {{attributeName}}().newPUTConnection(connectToken, consumer);
// TODO wildcard-topic not supported yet
consumer.accept("", input.getBytes());
});
break; break;
{{/InUse}} {{/InUse}}
{{/restHandler}} {{/restHandler}}
...@@ -173,7 +170,10 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam ...@@ -173,7 +170,10 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
{{/restHandler}} {{/restHandler}}
{{#restClientHandler}} {{#restClientHandler}}
{{#InUse}} {{#InUse}}
case "rest": disconnectingMethod = {{attributeName}}()::disconnect; case "restClient": disconnectingMethod = token -> {
{{receiverName}} = null;
return true;
};
break; break;
{{/InUse}} {{/InUse}}
{{/restClientHandler}} {{/restClientHandler}}
......
...@@ -54,12 +54,28 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete ...@@ -54,12 +54,28 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete
case "rest": { case "rest": {
success = {{attributeName}}().newGETConnection(connectToken, () -> { success = {{attributeName}}().newGETConnection(connectToken, () -> {
{{updateMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); {{updateMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}});
return new String({{lastValueGetterCall}}); return {{lastValueGetterCall}};
}); });
break; break;
} }
{{/InUse}} {{/InUse}}
{{/restHandler}} {{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
case "restClient":
RestClientPreparedRequest preparedRequest = {{attributeName}}().preparePut(uri);
{{senderName}}.add(() -> {
{{! sync or async could be selected via options, see issue #62 }}
{{attributeName}}().sendRequestSync(preparedRequest, {{lastValueGetterCall}});
}{{#IndexBasedListAccess}}, index{{/IndexBasedListAccess}}, connectToken);
{{updateMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}});
if (writeCurrentValue) {
{{writeMethodName}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}connectToken);
}
success = true;
break;
{{/InUse}}
{{/restClientHandler}}
default: default:
{{logError}}("Unknown protocol '{{log_}}'.", scheme); {{logError}}("Unknown protocol '{{log_}}'.", scheme);
success = false; success = false;
...@@ -121,6 +137,13 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam ...@@ -121,6 +137,13 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
break; break;
{{/InUse}} {{/InUse}}
{{/restHandler}} {{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
case "restClient":
disconnectingMethod = {{senderName}}::remove;
break;
{{/InUse}}
{{/restClientHandler}}
default: default:
{{logError}}("Unknown protocol '{{log_}}' in '{{log_}}' for disconnecting {{parentTypeName}}.{{entityName}}", {{logError}}("Unknown protocol '{{log_}}' in '{{log_}}' for disconnecting {{parentTypeName}}.{{entityName}}",
scheme, {{connectParameterName}}); scheme, {{connectParameterName}});
...@@ -165,9 +188,6 @@ protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}i ...@@ -165,9 +188,6 @@ protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}i
{{#needForwarding}} {{#needForwarding}}
syn {{{forwardingType}}} {{parentTypeName}}.{{forwardingName}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) { syn {{{forwardingType}}} {{parentTypeName}}.{{forwardingName}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) {
{{#relationPortWithListRole}} {{#relationPortWithListRole}}
// for (var element : {{realGetterMethodCall}}) {
// element.{{touchedTerminalsMethodName}}();
// }
{{realGetterMethodCall}}.stream().forEach(element -> element.{{touchedTerminalsMethodName}}()); {{realGetterMethodCall}}.stream().forEach(element -> element.{{touchedTerminalsMethodName}}());
return {{realGetterMethodCall}}; return {{realGetterMethodCall}};
{{/relationPortWithListRole}} {{/relationPortWithListRole}}
......
...@@ -712,6 +712,28 @@ task compileJavaIncremental(type: RagConnectTest) { ...@@ -712,6 +712,28 @@ task compileJavaIncremental(type: RagConnectTest) {
} }
} }
// --- Test: rest-client-server ---
task compileRestClientServerTest(type: RagConnectTest) {
ragconnect {
outputDir = file('src/test/02-after-ragconnect/restClientServer')
inputFiles = [file('src/test/01-input/restClientServer/Test.relast'),
file('src/test/01-input/restClientServer/Test.connect')]
rootNode = 'Root'
protocols = ['rest','restClient']
extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329'])
}
relast {
useJastAddNames = true
grammarName = 'src/test/03-after-relast/restClientServer/restClientServer'
serializer = 'jackson'
}
jastadd {
jastAddList = 'JastAddList'
packageName = 'restClientServer.ast'
extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL
}
}
// --- Task order --- // --- Task order ---
classes.dependsOn(':ragconnect.base:jar') classes.dependsOn(':ragconnect.base:jar')
......
send SenderRoot.SimpleValue ;
receive ReceiverRoot.ReceivedValue ;
send SenderRoot.SingleA ;
receive ReceiverRoot.SomeA ;
Root ::= SenderRoot ReceiverRoot;
SenderRoot ::= <SimpleValue:int> SingleA:A ;
ReceiverRoot ::= <ReceivedValue:int> SomeA:A ;
A ::= <Value> Inner ;
Inner ::= <InnerValue> ;
package org.jastadd.ragconnect.tests;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import restClientServer.ast.*;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Testing RestClient.
*
* @author rschoene - Initial contribution
*/
public class RestClientServerTest extends RagConnectTest {
private Root root;
@Test
public void testSimpleSenderRest() throws IOException {
root.getSenderRoot().setSimpleValue(1);
assertThat(root.getReceiverRoot().connectReceivedValue("restClient://localhost:4567/serve-simple")).isTrue();
assertThat(root.getSenderRoot().connectSimpleValue("rest://localhost:4567/serve-simple", true)).isTrue();
assertThat(root.getReceiverRoot().getReceivedValue()).isEqualTo(1);
root.getSenderRoot().setSimpleValue(2);
assertThat(root.getReceiverRoot().getReceivedValue()).isEqualTo(2);
}
@Test
public void testSimpleSenderRestClient() throws IOException {
root.getSenderRoot().setSimpleValue(1);
assertThat(root.getReceiverRoot().connectReceivedValue("rest://localhost:4567/put-simple")).isTrue();
assertThat(root.getSenderRoot().connectSimpleValue("restClient://localhost:4567/put-simple", true)).isTrue();
assertThat(root.getReceiverRoot().getReceivedValue()).isEqualTo(1);
root.getSenderRoot().setSimpleValue(2);
assertThat(root.getReceiverRoot().getReceivedValue()).isEqualTo(2);
}
// @Test
// public void testA() throws IOException {
// A a2 = new A().setName("a2");
// model.addMultiple(a2);
// a2.setId(11);
// assertThat(a2.connectId("restClient://localhost:5000/write-single-a", true)).isTrue();
// a2.setId(23);
// }
@BeforeEach
public void createModel() {
root = new Root();
root.setReceiverRoot(new ReceiverRoot());
root.setSenderRoot(new SenderRoot());
}
@AfterEach
public void close() {
root.ragconnectCloseConnections();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment