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

WIP: restClient receiving for tokens.

- missing tests
- missing close
- missing disconnect
parent 784cf03d
No related branches found
No related tags found
1 merge request!38Resolve "New Handler: REST client"
Pipeline #16346 passed
...@@ -5,9 +5,9 @@ To add a new communication protocol, the following locations have to be changed ...@@ -5,9 +5,9 @@ To add a new communication protocol, the following locations have to be changed
### Within `ragconnect.base/src/main/resources` ### Within `ragconnect.base/src/main/resources`
{% raw %} {% 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 `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 %} {% endraw %}
### Within `ragconnect.base/src/main/jastadd` ### Within `ragconnect.base/src/main/jastadd`
...@@ -18,7 +18,7 @@ In `Handlers.jrag`: Add a new attribute `RagConnect.abcHandler()` returning the ...@@ -18,7 +18,7 @@ In `Handlers.jrag`: Add a new attribute `RagConnect.abcHandler()` returning the
In `Compiler.java`: In `Compiler.java`:
- Add a new choice for `--protocols` similar to the existing ones - 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). Furthermore, new test cases are appreciated, see [below](#writing-tests).
......
...@@ -112,7 +112,7 @@ aspect Analysis { ...@@ -112,7 +112,7 @@ aspect Analysis {
return !getDependencySourceDefinitionList().isEmpty() || return !getDependencySourceDefinitionList().isEmpty() ||
getTokenPortTargetList().stream() getTokenPortTargetList().stream()
.map(PortTarget::containingPortDefinition) .map(PortTarget::containingPortDefinition)
.anyMatch(PortDefinition::shouldNotResetValue); .anyMatch(def -> def.shouldNotResetValue() || ragconnect().restClientHandler().getInUse());
} }
// --- effectiveUsedAt --- // --- effectiveUsedAt ---
......
...@@ -2,6 +2,7 @@ aspect RagConnectHandlers { ...@@ -2,6 +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");
private Handler RagConnect.resolveHandlerByName(String uniqueName) { private Handler RagConnect.resolveHandlerByName(String uniqueName) {
for (Handler handler : getHandlerList()) { for (Handler handler : getHandlerList()) {
......
...@@ -232,7 +232,8 @@ aspect MustacheMappingApplicationAndDefinition { ...@@ -232,7 +232,8 @@ aspect MustacheMappingApplicationAndDefinition {
eq MRelationSendDefinition.preemptiveReturn() = "return false;"; eq MRelationSendDefinition.preemptiveReturn() = "return false;";
eq MTokenReceiveDefinition.firstInputVarName() = "message"; 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 MTokenReceiveDefinition.preemptiveReturn() = "return;";
eq MTokenSendDefinition.firstInputVarName() = getterMethodCall(); eq MTokenSendDefinition.firstInputVarName() = getterMethodCall();
...@@ -525,6 +526,7 @@ aspect MustacheSendDefinition { ...@@ -525,6 +526,7 @@ aspect MustacheSendDefinition {
syn boolean PortDefinition.relationPortWithListRole() = getPortTarget().relationPortWithListRole(); syn boolean PortDefinition.relationPortWithListRole() = getPortTarget().relationPortWithListRole();
syn String PortDefinition.receiverName() = getPortTarget().receiverName();
syn String PortDefinition.senderName() = getPortTarget().senderName(); syn String PortDefinition.senderName() = getPortTarget().senderName();
syn java.util.List<SendIncrementalObserverEntry> PortDefinition.sendIncrementalObserverEntries() { syn java.util.List<SendIncrementalObserverEntry> PortDefinition.sendIncrementalObserverEntries() {
...@@ -583,6 +585,9 @@ containingPortDefinition().getIndexBasedListAccess()); ...@@ -583,6 +585,9 @@ containingPortDefinition().getIndexBasedListAccess());
syn boolean PortTarget.relationPortWithListRole() = false; syn boolean PortTarget.relationPortWithListRole() = false;
eq RelationPortTarget.relationPortWithListRole() = getRole().isListRole(); 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(); syn String PortTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + entityName();
eq ContextFreeTypePortTarget.senderName() = null; eq ContextFreeTypePortTarget.senderName() = null;
...@@ -645,6 +650,16 @@ aspect MustacheTokenComponent { ...@@ -645,6 +650,16 @@ aspect MustacheTokenComponent {
syn String TokenComponent.javaType() = effectiveJavaTypeUse().prettyPrint(); 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() { syn PortDefinition TokenComponent.normalTokenSendDef() {
for (Component comp : meOwnedByOthers()) { for (Component comp : meOwnedByOthers()) {
PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenSendDef(); PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenSendDef();
...@@ -682,6 +697,15 @@ aspect MustacheTokenComponent { ...@@ -682,6 +697,15 @@ aspect MustacheTokenComponent {
// > see MustacheSend for updateMethodName, writeMethodName // > see MustacheSend for updateMethodName, writeMethodName
// === attributes needed for computing above ones === // === attributes needed for computing above ones ===
syn PortDefinition TokenComponent.directNormalTokenReceiveDef() {
for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && ragconnect().restClientHandler().getInUse()) {
return target.containingPortDefinition();
}
}
return null;
}
syn PortDefinition TokenComponent.directNormalTokenSendDef() { syn PortDefinition TokenComponent.directNormalTokenSendDef() {
for (PortTarget target : getTokenPortTargetList()) { for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) { if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) {
......
...@@ -39,6 +39,7 @@ public class Compiler extends AbstractCompiler { ...@@ -39,6 +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";
public Compiler() { public Compiler() {
super("ragconnect", true); super("ragconnect", true);
...@@ -183,6 +184,7 @@ public class Compiler extends AbstractCompiler { ...@@ -183,6 +184,7 @@ public class Compiler extends AbstractCompiler {
.addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT") .addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT")
.addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java (experimental)") .addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java (experimental)")
.addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST") .addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST")
.addAcceptedValue(OPTION_PROTOCOL_REST_CLIENT, "Enable REST client (experimental)")
); );
optionPrintYaml = addOption( optionPrintYaml = addOption(
new BooleanOption("printYaml", "Print out YAML instead of generating files and exit.") new BooleanOption("printYaml", "Print out YAML instead of generating files and exit.")
...@@ -341,6 +343,8 @@ public class Compiler extends AbstractCompiler { ...@@ -341,6 +343,8 @@ 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",
optionProtocols.hasValue(OPTION_PROTOCOL_REST_CLIENT)));
} }
public String generateAspect(RagConnect ragConnect) { public String generateAspect(RagConnect ragConnect) {
......
// dispatch depending on URI. might not be necessary
public class RestClientServerHandler {
public RestClientServerHandler(String name) {
// TODO implement
}
RestClientHandler singleton = new RestClientHandler();
// TODO create handler based on URI
public RagConnectReceiver newReceiverFor(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) {
return singleton.newReceiverFor(connectToken, callback);
}
public boolean disconnect(RagConnectToken connectToken) {
// TODO implement
return false;
}
public void close() {
// TODO implement
}
}
public class RestClientHandler {
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"));
return () -> {
byte[] rawInput;
try {
rawInput = fetchFrom(target);
} catch (Exception e) {
{{logException}}("Exception when fetching from " + target, e);
return;
}
callback.accept("", rawInput);
};
}
byte[] fetchFrom(java.net.URI uri) throws java.io.IOException, InterruptedException {
// TODO the request should only be built once, and not every time the GET call is run
java.net.http.HttpRequest httpRequest = java.net.http.HttpRequest.newBuilder()
.uri(uri)
.GET()
.build();
java.net.http.HttpClient httpClient = java.net.http.HttpClient.newHttpClient();
java.net.http.HttpResponse<byte[]> response = httpClient.send(httpRequest,
java.net.http.HttpResponse.BodyHandlers.ofByteArray());
return response.body();
}
}
...@@ -46,6 +46,12 @@ aspect RagConnectHandler { ...@@ -46,6 +46,12 @@ aspect RagConnectHandler {
{{/InUse}} {{/InUse}}
{{/restHandler}} {{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
{{> RestClientHandler}}
{{/InUse}}
{{/restClientHandler}}
class RagConnectToken { class RagConnectToken {
static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0); static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0);
final long id; final long id;
...@@ -191,4 +197,7 @@ aspect RagConnectHandler { ...@@ -191,4 +197,7 @@ aspect RagConnectHandler {
java.util.Optional.ofNullable(publishers.get(index)).ifPresent(publisher -> publisher.setLastValue(value)); java.util.Optional.ofNullable(publishers.get(index)).ifPresent(publisher -> publisher.setLastValue(value));
} }
} }
interface RagConnectReceiver extends Runnable {
}
} }
private RagConnectReceiver {{parentTypeName}}.{{receiverName}} = null;
{{#typeIsList}} {{#typeIsList}}
{{#IndexBasedListAccess}} {{#IndexBasedListAccess}}
private int {{parentTypeName}}.{{resolveInListMethodName}}(String topic) { private int {{parentTypeName}}.{{resolveInListMethodName}}(String topic) {
...@@ -123,6 +125,14 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec ...@@ -123,6 +125,14 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec
break; break;
{{/InUse}} {{/InUse}}
{{/restHandler}} {{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
case "restClient":
{{receiverName}} = {{attributeName}}().newReceiverFor(connectToken, consumer);
success = {{receiverName}} != null;
break;
{{/InUse}}
{{/restClientHandler}}
default: default:
{{logError}}("Unknown protocol '{{log_}}'.", scheme); {{logError}}("Unknown protocol '{{log_}}'.", scheme);
success = false; success = false;
...@@ -161,6 +171,12 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam ...@@ -161,6 +171,12 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
break; break;
{{/InUse}} {{/InUse}}
{{/restHandler}} {{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
case "rest": disconnectingMethod = {{attributeName}}()::disconnect;
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}});
......
...@@ -18,5 +18,10 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) { ...@@ -18,5 +18,10 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) {
} }
public {{javaType}} {{parentTypeName}}.get{{Name}}() { public {{javaType}} {{parentTypeName}}.get{{Name}}() {
{{#normalTokenReceiveDef}}
if ({{receiverName}} != null) {
{{receiverName}}.run();
}
{{/normalTokenReceiveDef}}
return get{{internalName}}(); return get{{internalName}}();
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment