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
### 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).
......
......@@ -112,7 +112,7 @@ aspect Analysis {
return !getDependencySourceDefinitionList().isEmpty() ||
getTokenPortTargetList().stream()
.map(PortTarget::containingPortDefinition)
.anyMatch(PortDefinition::shouldNotResetValue);
.anyMatch(def -> def.shouldNotResetValue() || ragconnect().restClientHandler().getInUse());
}
// --- 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("rest_client");
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();
......@@ -525,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() {
......@@ -583,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;
......@@ -645,6 +650,16 @@ aspect MustacheTokenComponent {
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 (Component comp : meOwnedByOthers()) {
PortDefinition maybeResult = comp.asTokenComponent().directNormalTokenSendDef();
......@@ -682,6 +697,15 @@ aspect MustacheTokenComponent {
// > see MustacheSend for updateMethodName, writeMethodName
// === 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() {
for (PortTarget target : getTokenPortTargetList()) {
if (target.isTokenPortTarget() && target.containingPortDefinition().shouldNotResetValue()) {
......
......@@ -39,6 +39,7 @@ public class Compiler extends AbstractCompiler {
private static final String OPTION_PROTOCOL_JAVA = "java";
private static final String OPTION_PROTOCOL_MQTT = "mqtt";
private static final String OPTION_PROTOCOL_REST = "rest";
private static final String OPTION_PROTOCOL_REST_CLIENT = "rest-client";
public Compiler() {
super("ragconnect", true);
......@@ -183,6 +184,7 @@ public class Compiler extends AbstractCompiler {
.addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT")
.addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java (experimental)")
.addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST")
.addAcceptedValue(OPTION_PROTOCOL_REST_CLIENT, "Enable REST client (experimental)")
);
optionPrintYaml = addOption(
new BooleanOption("printYaml", "Print out YAML instead of generating files and exit.")
......@@ -341,6 +343,8 @@ public class Compiler extends AbstractCompiler {
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("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) {
......
// 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 {
{{/InUse}}
{{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
{{> RestClientHandler}}
{{/InUse}}
{{/restClientHandler}}
class RagConnectToken {
static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0);
final long id;
......@@ -191,4 +197,7 @@ aspect RagConnectHandler {
java.util.Optional.ofNullable(publishers.get(index)).ifPresent(publisher -> publisher.setLastValue(value));
}
}
interface RagConnectReceiver extends Runnable {
}
}
private RagConnectReceiver {{parentTypeName}}.{{receiverName}} = null;
{{#typeIsList}}
{{#IndexBasedListAccess}}
private int {{parentTypeName}}.{{resolveInListMethodName}}(String topic) {
......@@ -123,6 +125,14 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec
break;
{{/InUse}}
{{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
case "restClient":
{{receiverName}} = {{attributeName}}().newReceiverFor(connectToken, consumer);
success = {{receiverName}} != null;
break;
{{/InUse}}
{{/restClientHandler}}
default:
{{logError}}("Unknown protocol '{{log_}}'.", scheme);
success = false;
......@@ -161,6 +171,12 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam
break;
{{/InUse}}
{{/restHandler}}
{{#restClientHandler}}
{{#InUse}}
case "rest": disconnectingMethod = {{attributeName}}()::disconnect;
break;
{{/InUse}}
{{/restClientHandler}}
default:
{{logError}}("Unknown protocol '{{log_}}' in '{{log_}}' for disconnecting {{parentTypeName}}.{{entityName}}",
scheme, {{connectParameterName}});
......
......@@ -18,5 +18,10 @@ public {{parentTypeName}} {{parentTypeName}}.set{{Name}}({{javaType}} value) {
}
public {{javaType}} {{parentTypeName}}.get{{Name}}() {
{{#normalTokenReceiveDef}}
if ({{receiverName}} != null) {
{{receiverName}}.run();
}
{{/normalTokenReceiveDef}}
return get{{internalName}}();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment