Skip to content

Commit

Permalink
Add oas gen support for service contract types
Browse files Browse the repository at this point in the history
  • Loading branch information
TharmiganK committed Jun 20, 2024
1 parent 5c9385b commit 7d249a3
Show file tree
Hide file tree
Showing 20 changed files with 272 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public final class Constants {
public static final String HTTP = "http";
public static final String BALLERINA = "ballerina";
public static final String EMPTY = "";
public static final String HTTP_SERVICE_CONTRACT = "ServiceContract";
public static final String INTERCEPTABLE_SERVICE = "InterceptableService";
public static final String NEXT_SERVICE = "NextService";
public static final String INTERCEPTOR = "Interceptor";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import io.ballerina.openapi.service.mapper.diagnostic.OpenAPIMapperDiagnostic;
import io.ballerina.openapi.service.mapper.model.OASResult;
import io.ballerina.openapi.service.mapper.model.OpenAPIInfo;
import io.ballerina.openapi.service.mapper.model.Service;
import io.ballerina.openapi.service.mapper.model.ServiceNode;
import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils;
import io.ballerina.tools.diagnostics.Location;
import io.swagger.v3.oas.models.OpenAPI;
Expand Down Expand Up @@ -85,12 +85,12 @@ public final class InfoMapper {
* @param ballerinaFilePath Ballerina file path.
* @return {@code OASResult}
*/
static OASResult getOASResultWithInfo(Service serviceNode, SemanticModel semanticModel, String openapiFileName,
static OASResult getOASResultWithInfo(ServiceNode serviceNode, SemanticModel semanticModel, String openapiFileName,
Path ballerinaFilePath) {
Optional<MetadataNode> metadata = serviceNode.metadata();
List<OpenAPIMapperDiagnostic> diagnostics = new ArrayList<>();
OpenAPI openAPI = new OpenAPI();
String currentServiceName = ServersMapper.getServiceBasePath(serviceNode);
String currentServiceName = serviceNode.absoluteResourcePath();
// 01. Set openAPI inFo section wit package details
String version = getContractVersion(serviceNode, semanticModel);
if (metadata.isPresent() && !metadata.get().annotations().isEmpty()) {
Expand Down Expand Up @@ -162,7 +162,7 @@ private static OASResult normalizeInfoSection(String openapiFileName, String cur
}

// Set contract version by default using package version.
private static String getContractVersion(Service serviceDefinition, SemanticModel semanticModel) {
private static String getContractVersion(ServiceNode serviceDefinition, SemanticModel semanticModel) {
Optional<Symbol> symbol = serviceDefinition.getSymbol(semanticModel);
String version = "1.0.0";
if (symbol.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,10 @@
*/
package io.ballerina.openapi.service.mapper;

import io.ballerina.compiler.syntax.tree.Node;
import io.ballerina.compiler.syntax.tree.NodeList;
import io.ballerina.openapi.service.mapper.model.Service;
import io.ballerina.openapi.service.mapper.utils.MapperCommonUtils;

/**
* The {@link ServersMapper} represents the interface for servers mapper.
*/
public interface ServersMapper {

void setServers();

/**
* Gets the base path of a mapper.
*
* @param serviceDefinition The mapper definition node.
* @return The base path.
*/
static String getServiceBasePath(Service serviceDefinition) {
StringBuilder currentServiceName = new StringBuilder();
NodeList<Node> serviceNameNodes = serviceDefinition.absoluteResourcePath();
for (Node serviceBasedPathNode : serviceNameNodes) {
currentServiceName.append(MapperCommonUtils.unescapeIdentifier(serviceBasedPathNode.toString()));
}
return currentServiceName.toString().trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import io.ballerina.compiler.syntax.tree.SeparatedNodeList;
import io.ballerina.compiler.syntax.tree.SpecificFieldNode;
import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.openapi.service.mapper.model.Service;
import io.ballerina.openapi.service.mapper.model.ServiceNode;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable;
Expand All @@ -57,15 +57,21 @@ public class ServersMapperImpl implements ServersMapper {

final OpenAPI openAPI;
final Set<ListenerDeclarationNode> endpoints;
final Service service;
final ServiceNode service;

public ServersMapperImpl(OpenAPI openAPI, Set<ListenerDeclarationNode> endpoints, Service service) {
public ServersMapperImpl(OpenAPI openAPI, Set<ListenerDeclarationNode> endpoints, ServiceNode service) {
this.openAPI = openAPI;
this.endpoints = endpoints;
this.service = service;
}

public void setServers() {
if (service.kind().equals(ServiceNode.Kind.SERVICE_OBJECT_TYPE)) {
Server defaultServer = getDefaultServerWithBasePath(service.absoluteResourcePath());
openAPI.setServers(Collections.singletonList(defaultServer));
return;
}

extractServerForExpressionNode();
List<Server> servers = openAPI.getServers();
//Handle ImplicitNewExpressionNode in listener
Expand All @@ -89,12 +95,12 @@ private void updateServerDetails(List<Server> servers, ListenerDeclarationNode e
if (expNode instanceof QualifiedNameReferenceNode refNode) {
//Handle QualifiedNameReferenceNode in listener
if (refNode.identifier().text().trim().equals(endPoint.variableName().text().trim())) {
String serviceBasePath = ServersMapper.getServiceBasePath(service);
String serviceBasePath = service.absoluteResourcePath();
Server server = extractServer(endPoint, serviceBasePath);
servers.add(server);
}
} else if (expNode.toString().trim().equals(endPoint.variableName().text().trim())) {
String serviceBasePath = ServersMapper.getServiceBasePath(service);
String serviceBasePath = service.absoluteResourcePath();
Server server = extractServer(endPoint, serviceBasePath);
servers.add(server);
}
Expand Down Expand Up @@ -151,7 +157,7 @@ private static Optional<ParenthesizedArgList> extractListenerNodeType(Node expre
// Function to handle ExplicitNewExpressionNode in listener.
private void extractServerForExpressionNode() {
SeparatedNodeList<ExpressionNode> bTypeExplicit = service.expressions();
String serviceBasePath = ServersMapper.getServiceBasePath(service);
String serviceBasePath = service.absoluteResourcePath();
Optional<ParenthesizedArgList> list;
List<Server> servers = new ArrayList<>();
for (ExpressionNode expressionNode: bTypeExplicit) {
Expand Down Expand Up @@ -265,4 +271,22 @@ private static String concatenateServerURL(String host, SeparatedNodeList<Mappin
}
return host;
}

private static Server getDefaultServerWithBasePath(String serviceBasePath) {
String serverUrl = String.format("{server}:{port}%s", serviceBasePath);
ServerVariables serverVariables = new ServerVariables();

ServerVariable serverUrlVariable = new ServerVariable();
serverUrlVariable._default("localhost");
serverVariables.addServerVariable(SERVER, serverUrlVariable);

ServerVariable portVariable = new ServerVariable();
portVariable._default("8080");
serverVariables.addServerVariable(PORT, portVariable);

Server server = new Server();
server.setUrl(serverUrl);
server.setVariables(serverVariables);
return server;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor;
import io.ballerina.openapi.service.mapper.model.OperationInventory;
import io.ballerina.openapi.service.mapper.model.ResourceFunction;
import io.ballerina.openapi.service.mapper.model.Service;
import io.ballerina.openapi.service.mapper.model.ServiceNode;
import io.ballerina.openapi.service.mapper.parameter.DefaultParameterMapper;
import io.ballerina.openapi.service.mapper.parameter.ParameterMapper;
import io.ballerina.openapi.service.mapper.parameter.ParameterMapperWithInterceptors;
Expand Down Expand Up @@ -83,7 +83,7 @@ public class ServiceMapperFactory {
private final InterceptorPipeline interceptorPipeline;

public ServiceMapperFactory(OpenAPI openAPI, SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor,
List<OpenAPIMapperDiagnostic> diagnostics, Service serviceDefinition) {
List<OpenAPIMapperDiagnostic> diagnostics, ServiceNode serviceDefinition) {
this.additionalData = new AdditionalData(semanticModel, moduleMemberVisitor, diagnostics);
this.treatNilableAsOptional = isTreatNilableAsOptionalParameter(serviceDefinition);
this.openAPI = openAPI;
Expand All @@ -94,7 +94,7 @@ public ServiceMapperFactory(OpenAPI openAPI, SemanticModel semanticModel, Module
this.hateoasMapper = new HateoasMapperImpl();
}

public ServersMapper getServersMapper(Set<ListenerDeclarationNode> endpoints, Service serviceNode) {
public ServersMapper getServersMapper(Set<ListenerDeclarationNode> endpoints, ServiceNode serviceNode) {
return new ServersMapperImpl(openAPI, endpoints, serviceNode);
}

Expand Down Expand Up @@ -174,7 +174,7 @@ private Components getComponents(OpenAPI openAPI) {
return components;
}

private static boolean isTreatNilableAsOptionalParameter(Service serviceNode) {
private static boolean isTreatNilableAsOptionalParameter(ServiceNode serviceNode) {
if (serviceNode.metadata().isEmpty()) {
return true;
}
Expand All @@ -192,7 +192,7 @@ private static boolean isTreatNilableAsOptionalParameter(Service serviceNode) {
return true;
}

private static boolean isInterceptableService(Service serviceDefinition, SemanticModel semanticModel) {
private static boolean isInterceptableService(ServiceNode serviceDefinition, SemanticModel semanticModel) {
boolean[] isInterceptable = {false};
serviceDefinition.getSymbol(semanticModel).ifPresent(symbol -> {
if (symbol instanceof ServiceDeclarationSymbol serviceSymbol) {
Expand All @@ -209,7 +209,7 @@ private static boolean isInterceptableService(Service serviceDefinition, Semanti
return isInterceptable[0];
}

private static InterceptorPipeline getInterceptorPipeline(Service serviceDefinition,
private static InterceptorPipeline getInterceptorPipeline(ServiceNode serviceDefinition,
AdditionalData additionalData) {
if (!isInterceptableService(serviceDefinition, additionalData.semanticModel())) {
return null;
Expand Down
Loading

0 comments on commit 7d249a3

Please sign in to comment.