Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Csharp codegen support exchange generation #159

Open
wants to merge 1 commit into
base: features/csharp_codegen_support_rest_reources_generation
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.vlingo.xoom.codegen.template.TemplateParameters;
import io.vlingo.xoom.codegen.template.TemplateStandard;
import io.vlingo.xoom.designer.codegen.CodeGenerationProperties;
import io.vlingo.xoom.designer.codegen.csharp.exchange.ExchangeRole;
import io.vlingo.xoom.designer.codegen.csharp.projections.ProjectionType;
import io.vlingo.xoom.designer.codegen.csharp.storage.Model;
import io.vlingo.xoom.designer.codegen.csharp.storage.StorageType;
Expand Down Expand Up @@ -129,6 +130,30 @@ public enum CsharpTemplateStandard implements TemplateStandard {
AUTO_DISPATCH_HANDLERS_MAPPING(parameters -> Template.AUTO_DISPATCH_HANDLERS_MAPPING.filename,
(name, parameters) -> name + "ResourceHandlers"),
AUTO_DISPATCH_ROUTE(parameters -> Template.AUTO_DISPATCH_ROUTE.filename),

EXCHANGE_BOOTSTRAP(parameters -> Template.EXCHANGE_BOOTSTRAP.filename,
(name, parameters) -> "ExchangeBootstrap"),

EXCHANGE_MAPPER(parameters -> parameters.<ExchangeRole>find(EXCHANGE_ROLE).isConsumer() ?
CONSUMER_EXCHANGE_MAPPER.filename : PRODUCER_EXCHANGE_MAPPER.filename,
(name, parameters) -> parameters.<ExchangeRole>find(EXCHANGE_ROLE).isConsumer() ?
parameters.find(LOCAL_TYPE_NAME) + "Mapper" : "DomainEventMapper"),

EXCHANGE_ADAPTER(parameters ->
parameters.<ExchangeRole>find(EXCHANGE_ROLE).isConsumer() ?
CONSUMER_EXCHANGE_ADAPTER.filename : PRODUCER_EXCHANGE_ADAPTER.filename,
(name, parameters) -> {
final ExchangeRole exchangeRole = parameters.find(EXCHANGE_ROLE);
if(exchangeRole.isConsumer()) {
return parameters.<String>find(LOCAL_TYPE_NAME) + "Adapter";
}
return parameters.<String>find(AGGREGATE_PROTOCOL_NAME) + exchangeRole.formatName() + "Adapter";
}),
EXCHANGE_RECEIVER_HOLDER(parameters -> Template.EXCHANGE_RECEIVER_HOLDER.filename,
(name, parameters) -> parameters.<String>find(AGGREGATE_PROTOCOL_NAME) +
"ExchangeReceivers"),
EXCHANGE_DISPATCHER(parameters -> Template.EXCHANGE_DISPATCHER.filename,
(name, parameters) -> "ExchangeDispatcher"),
;

private final Function<TemplateParameters, String> templateFileRetriever;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright © 2012-2022 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.
package io.vlingo.xoom.designer.codegen.csharp;

import io.vlingo.xoom.designer.codegen.DeploymentType;

public class DeploymentSettings {

public final DeploymentType type;
public final String dockerImage;
public final String kubernetesPod;
public final String kubernetesImage;
public final int producerExchangePort;
public final boolean useDocker;
public final boolean useKubernetes;

public static DeploymentSettings with(final DeploymentType type,
final String dockerImage,
final String kubernetesImage,
final String kubernetesPod,
final int producerExchangePort) {
return new DeploymentSettings(type, dockerImage, kubernetesImage, kubernetesPod, producerExchangePort);
}

private DeploymentSettings(final DeploymentType type,
final String dockerImage,
final String kubernetesImage,
final String kubernetesPod,
final int producerExchangePort) {
this.type = type;
this.dockerImage = dockerImage;
this.kubernetesPod = kubernetesPod;
this.kubernetesImage = kubernetesImage;
this.useDocker = type.isDocker() || type.isKubernetes();
this.useKubernetes = type.isKubernetes();
this.producerExchangePort = producerExchangePort;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright © 2012-2022 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.
package io.vlingo.xoom.designer.codegen.csharp;

import io.vlingo.xoom.codegen.parameter.CodeGenerationParameter;
import io.vlingo.xoom.designer.codegen.Label;
import io.vlingo.xoom.designer.codegen.csharp.exchange.ExchangeRole;
import io.vlingo.xoom.designer.codegen.csharp.exchange.Schema;

import java.util.stream.Stream;

public class ExchangeDetail {

public static Stream<CodeGenerationParameter> findInvolvedStateFieldsOnReceivers(final CodeGenerationParameter exchange) {
final CodeGenerationParameter aggregate = exchange.parent();
return exchange.retrieveAllRelated(Label.RECEIVER).flatMap(receiver -> {
final String methodName = receiver.retrieveRelatedValue(Label.MODEL_METHOD);
return AggregateDetail.findInvolvedStateFields(aggregate, methodName);
});
}

public static Stream<String> findConsumedQualifiedEventNames(final CodeGenerationParameter exchange) {
if(exchange.retrieveRelatedValue(Label.ROLE, ExchangeRole::of).isProducer()) {
return Stream.empty();
}
return exchange.retrieveAllRelated(Label.RECEIVER)
.map(receiver -> receiver.retrieveOneRelated(Label.SCHEMA).<Schema>object())
.map(Schema::qualifiedName).distinct();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,8 @@ private static Label resolveFieldTypeLabel(final CodeGenerationParameter parent)
}
throw new IllegalArgumentException("Unable to resolve field type of " + parent.label);
}

public static String genericTypeOf(final CodeGenerationParameter parent, final String fieldName) {
return genericTypeOf(typeOf(parent, fieldName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ public enum Template {
AUTO_DISPATCH_MAPPING("AutoDispatchMapping"),
AUTO_DISPATCH_ROUTE("AutoDispatchRoute"),
AUTO_DISPATCH_HANDLERS_MAPPING("AutoDispatchHandlersMapping"),
AUTO_DISPATCH_HANDLER_ENTRY("AutoDispatchHandlerEntry"),;
AUTO_DISPATCH_HANDLER_ENTRY("AutoDispatchHandlerEntry"),
EXCHANGE_RECEIVER_HOLDER("ExchangeReceiverHolder"),
EXCHANGE_BOOTSTRAP("ExchangeBootstrap"),
CONSUMER_EXCHANGE_MAPPER("ConsumerExchangeMapper"),
PRODUCER_EXCHANGE_MAPPER("ProducerExchangeMapper"),
CONSUMER_EXCHANGE_ADAPTER("ConsumerExchangeAdapter"),
PRODUCER_EXCHANGE_ADAPTER("ProducerExchangeAdapter"),
EXCHANGE_DISPATCHER("ExchangeDispatcher"),;

public final String filename;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,17 @@ public enum TemplateParameter implements ParameterKey {
HANDLER_INDEXES("handlerIndexes"),
HANDLER_ENTRIES("handlerEntries"),
FACTORY_METHOD("factoryMethod"),
INDEX_NAME("indexName"), ;
INDEX_NAME("indexName"),
EXCHANGE_ROLE("exchangeRole"),
LOCAL_TYPE_NAME("localTypeName"),
SCHEMA_GROUP_NAME("schemaGroupName"),
EXCHANGE_MAPPER_NAME("exchangeMapperName"),
EXCHANGE_ADAPTER_NAME("exchangeAdapterName"),
EXCHANGE_RECEIVERS("exchangeReceivers"),
EXCHANGE_RECEIVER_HOLDER_NAME("exchangeReceiverHolderName"),
PRODUCER_EXCHANGES("producerExchanges"),
EXCHANGES("exchanges"),
INLINE_EXCHANGE_NAMES("inlineExchangeNames"),;

public final String key;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright © 2012-2022 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.xoom.designer.codegen.csharp.exchange;

import io.vlingo.xoom.codegen.parameter.CodeGenerationParameter;
import io.vlingo.xoom.codegen.template.TemplateParameters;
import io.vlingo.xoom.designer.codegen.Label;
import io.vlingo.xoom.designer.codegen.csharp.CsharpTemplateStandard;
import io.vlingo.xoom.designer.codegen.csharp.TemplateParameter;
import io.vlingo.xoom.lattice.model.IdentifiedDomainEvent;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CoveyParameter {

public final String localClass;
public final String externalClass;
public final String adapterInstantiation;
public final String receiverInstantiation;
public final String qualifiedLocalClassName;

public static Set<CoveyParameter> from(final List<CodeGenerationParameter> exchanges) {
final Predicate<CodeGenerationParameter> onlyConsumers =
exchange -> exchange.retrieveRelatedValue(Label.ROLE, ExchangeRole::of).isConsumer();

final Predicate<CodeGenerationParameter> onlyProducers =
exchange -> exchange.retrieveRelatedValue(Label.ROLE, ExchangeRole::of).isProducer();

final Set<CoveyParameter> consumerCoveys =
exchanges.stream().filter(onlyConsumers)
.flatMap(exchange -> exchange.retrieveAllRelated(Label.RECEIVER))
.map(receiver -> new CoveyParameter(receiver.parent(Label.EXCHANGE), receiver.retrieveOneRelated(Label.SCHEMA).object()))
.collect(Collectors.toSet());

final Set<CoveyParameter> producerCoveys =
exchanges.stream().filter(onlyProducers).map(CoveyParameter::new).collect(Collectors.toSet());

return Stream.of(consumerCoveys, producerCoveys).flatMap(Set::stream).collect(Collectors.toSet());
}

private CoveyParameter(final CodeGenerationParameter consumerExchange, final Schema schema) {
this.localClass = schema.simpleClassName();
this.externalClass = String.class.getSimpleName();
this.adapterInstantiation = resolveConsumerAdapterInstantiation(schema);
this.receiverInstantiation = String.format("new %s(stage)", resolveReceiverName(consumerExchange, schema));
this.qualifiedLocalClassName = schema.qualifiedName();
}

private CoveyParameter(final CodeGenerationParameter producerExchange) {
this.localClass = IdentifiedDomainEvent.class.getSimpleName();
this.externalClass = IdentifiedDomainEvent.class.getSimpleName();
this.adapterInstantiation = String.format("new %s()", resolveProducerAdapterName(producerExchange));
this.receiverInstantiation = "received => {}";
this.qualifiedLocalClassName = IdentifiedDomainEvent.class.getCanonicalName();
}

private String resolveConsumerAdapterInstantiation(final Schema schema) {
return String.format("new %s(\"%s\")", resolveConsumerAdapterName(schema), schema.reference);
}

private String resolveReceiverName(final CodeGenerationParameter consumerExchange, final Schema schema) {
final TemplateParameters aggregateProtocolName =
TemplateParameters.with(TemplateParameter.AGGREGATE_PROTOCOL_NAME, consumerExchange.parent().value);

final String holderName =
CsharpTemplateStandard.EXCHANGE_RECEIVER_HOLDER.resolveClassname(aggregateProtocolName);

return String.format("%s.%s", holderName, schema.innerReceiverClassName());
}

private String resolveProducerAdapterName(final CodeGenerationParameter exchange) {
final TemplateParameters parameters = TemplateParameters.with(TemplateParameter.AGGREGATE_PROTOCOL_NAME, exchange.parent().value)
.and(TemplateParameter.EXCHANGE_ROLE, ExchangeRole.PRODUCER);
return CsharpTemplateStandard.EXCHANGE_ADAPTER.resolveClassname(parameters);
}

private String resolveConsumerAdapterName(final Schema schema) {
final TemplateParameters parameters = TemplateParameters.with(TemplateParameter.LOCAL_TYPE_NAME, schema.simpleClassName())
.and(TemplateParameter.EXCHANGE_ROLE, ExchangeRole.CONSUMER);

return CsharpTemplateStandard.EXCHANGE_ADAPTER.resolveClassname(parameters);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CoveyParameter that = (CoveyParameter) o;
return Objects.equals(localClass, that.localClass) &&
Objects.equals(adapterInstantiation, that.adapterInstantiation) &&
Objects.equals(externalClass, that.externalClass) &&
Objects.equals(receiverInstantiation, that.receiverInstantiation);
}

@Override
public int hashCode() {
return Objects.hash(localClass, adapterInstantiation, externalClass, receiverInstantiation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright © 2012-2022 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.xoom.designer.codegen.csharp.exchange;

import io.vlingo.xoom.codegen.parameter.CodeGenerationParameter;
import io.vlingo.xoom.designer.codegen.Label;
import io.vlingo.xoom.designer.codegen.csharp.CsharpTemplateStandard;

import java.util.*;
import java.util.stream.Collectors;

public class Exchange {

public final String name;
public final String dataObjectName;
public final String variableName;
public final String settingsName;
public final Set<CoveyParameter> coveys;
public final Set<ExchangeRole> roles = new HashSet<>();

public static List<Exchange> from(final List<CodeGenerationParameter> aggregates) {

final Map<String, Exchange> exchanges = new HashMap<>();

final List<CodeGenerationParameter> allExchanges =
aggregates.stream().flatMap(aggregate -> aggregate.retrieveAllRelated(Label.EXCHANGE))
.collect(Collectors.toList());

aggregates.forEach(aggregate -> {
aggregate.retrieveAllRelated(Label.EXCHANGE).forEach(exchangeParam -> {
final ExchangeRole exchangeRole =
exchangeParam.retrieveRelatedValue(Label.ROLE, ExchangeRole::of);

final Exchange exchange = new Exchange(aggregate.value, exchangeParam, allExchanges);

exchanges.computeIfAbsent(exchangeParam.value, e -> exchange).addRole(exchangeRole);
});
});

return new ArrayList<>(exchanges.values());
}

private Exchange(final String aggregateName, final CodeGenerationParameter exchange,
final List<CodeGenerationParameter> allExchangeParameters) {
this.name = exchange.value;
this.coveys = resolveCoveyParameters(exchange.value, allExchangeParameters);
this.variableName = Formatter.formatExchangeVariableName(exchange.value);
this.settingsName = variableName + "Settings";
this.dataObjectName = CsharpTemplateStandard.DATA_OBJECT.resolveClassname(aggregateName);
}

private Set<CoveyParameter> resolveCoveyParameters(final String exchangeName,
final List<CodeGenerationParameter> allExchangeParameters) {
final List<CodeGenerationParameter> relatedExchangeParameters = allExchangeParameters.stream()
.filter(exchange -> exchange.value.equals(exchangeName))
.collect(Collectors.toList());

return CoveyParameter.from(relatedExchangeParameters);
}

private Exchange addRole(final ExchangeRole exchangeRole) {
this.roles.add(exchangeRole);
return this;
}

public boolean isProducer() {
return this.roles.contains(ExchangeRole.PRODUCER);
}

public boolean isConsumer() {
return this.roles.contains(ExchangeRole.CONSUMER);
}
}