Skip to content

Commit

Permalink
Add enums for error codes
Browse files Browse the repository at this point in the history
  • Loading branch information
chamil321 committed Apr 19, 2021
1 parent 9aa9ae6 commit cb735d1
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 91 deletions.
1 change: 1 addition & 0 deletions http-compiler-plugin-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ task copyPackageBala {
}

test {
systemProperty "ballerina.offline.flag", "true"
useTestNG()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;

Expand All @@ -40,7 +39,6 @@ public class CompilerPluginTest {

private static final Path RESOURCE_DIRECTORY = Paths.get("src", "test", "resources", "ballerina_sources")
.toAbsolutePath();
private static final PrintStream OUT = System.out;
private static final Path DISTRIBUTION_PATH = Paths.get("build", "target", "ballerina-distribution")
.toAbsolutePath();

Expand All @@ -58,7 +56,7 @@ public class CompilerPluginTest {
private static final String HTTP_112 = "HTTP_112";
private static final String HTTP_113 = "HTTP_113";

private static final String REMOTE_METHODS_NOT_ALLOWED = "`remote` methods are not allowed in http:Service";
private static final String REMOTE_METHODS_NOT_ALLOWED = "remote methods are not allowed in http:Service";

private Package loadPackage(String path) {
Path projectDirPath = RESOURCE_DIRECTORY.resolve(path);
Expand Down Expand Up @@ -89,9 +87,10 @@ public void testInvalidMethodTypes() {
PackageCompilation compilation = currentPackage.getCompilation();
DiagnosticResult diagnosticResult = compilation.diagnosticResult();
Assert.assertEquals(diagnosticResult.diagnosticCount(), 3);
assertError(diagnosticResult, 0, REMOTE_METHODS_NOT_ALLOWED, HTTP_101);
assertError(diagnosticResult, 1, REMOTE_METHODS_NOT_ALLOWED, HTTP_101);
assertError(diagnosticResult, 2, REMOTE_METHODS_NOT_ALLOWED, HTTP_101);
diagnosticResult.diagnostics().forEach(result -> {
Assert.assertEquals(result.diagnosticInfo().messageFormat(), REMOTE_METHODS_NOT_ALLOWED);
Assert.assertEquals(result.diagnosticInfo().code(), HTTP_101);
});
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,6 @@
* Constants related to compiler plugin implementation.
*/
public class Constants {

public static final String HTTP_101 = "HTTP_101";
public static final String HTTP_102 = "HTTP_102";
public static final String HTTP_103 = "HTTP_103";
public static final String HTTP_104 = "HTTP_104";
public static final String HTTP_105 = "HTTP_105";
public static final String HTTP_106 = "HTTP_106";
public static final String HTTP_107 = "HTTP_107";
public static final String HTTP_108 = "HTTP_108";
public static final String HTTP_109 = "HTTP_109";
public static final String HTTP_110 = "HTTP_110";
public static final String HTTP_111 = "HTTP_111";
public static final String HTTP_112 = "HTTP_112";
public static final String HTTP_113 = "HTTP_113";

public static final String BALLERINA = "ballerina";
public static final String HTTP = "http";
public static final String REMOTE_KEYWORD = "remote";
Expand All @@ -49,5 +34,4 @@ public class Constants {
public static final String CALLER_ANNOTATION_TYPE = "HttpCallerInfo";
public static final String HEADER_ANNOTATION_TYPE = "HttpHeader";
public static final String ALLOWED_RETURN_UNION = "anydata|http:Response|http:StatusCodeRecord|error";
public static final String REMOTE_METHODS_NOT_ALLOWED = "`remote` methods are not allowed in http:Service";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.ballerina.stdlib.http.compiler;

import io.ballerina.tools.diagnostics.DiagnosticSeverity;

import static io.ballerina.stdlib.http.compiler.Constants.ALLOWED_RETURN_UNION;
import static io.ballerina.stdlib.http.compiler.Constants.RESOURCE_CONFIG_ANNOTATION;
import static io.ballerina.tools.diagnostics.DiagnosticSeverity.ERROR;

/**
* {@code DiagnosticCodes} is used to hold diagnostic codes.
*/
public enum HttpDiagnosticCodes {
HTTP_101("HTTP_101", "remote methods are not allowed in http:Service", ERROR),
HTTP_102("HTTP_102", "invalid resource method return type: expected '" + ALLOWED_RETURN_UNION +
"', but found '%s'", ERROR),
HTTP_103("HTTP_103", "invalid resource method annotation type: expected 'http:" + RESOURCE_CONFIG_ANNOTATION +
"', but found '%s'", ERROR),
HTTP_104("HTTP_104", "invalid annotation type on param '%s': expected one of the following types: " +
"'http:Payload', 'http:CallerInfo', 'http:Headers'", ERROR),
HTTP_105("HTTP_105", "invalid resource parameter '%s'", ERROR),
HTTP_106("HTTP_106", "invalid resource parameter type: '%s'", ERROR),
HTTP_107("HTTP_107", "invalid payload parameter type: '%s'", ERROR),
HTTP_108("HTTP_108", "invalid multiple resource parameter annotations for '%s'" +
": expected one of the following types: 'http:Payload', 'http:CallerInfo', 'http:Headers'", ERROR),
HTTP_109("HTTP_109", "invalid type of header param '%s': expected 'string' or 'string[]'", ERROR),
HTTP_110("HTTP_110", "invalid union type of header param '%s': a string or an array of a string can " +
"only be union with '()'. Eg: string|() or string[]|()", ERROR),
HTTP_111("HTTP_111", "invalid type of caller param '%s': expected 'http:Caller'", ERROR),
HTTP_112("HTTP_112", "invalid type of query param '%s': expected one of the 'string', 'int', 'float', " +
"'boolean', 'decimal' types or the array types of them", ERROR),
HTTP_113("HTTP_113", "invalid union type of query param '%s': 'string', 'int', 'float', 'boolean', " +
"'decimal' type or the array types of them can only be union with '()'. Eg: string? or int[]?", ERROR);

private final String code;
private final String message;
private final DiagnosticSeverity severity;

HttpDiagnosticCodes(String code, String message, DiagnosticSeverity severity) {
this.code = code;
this.message = message;
this.severity = severity;
}

public String getCode() {
return code;
}

public String getMessage() {
return message;
}

public DiagnosticSeverity getSeverity() {
return severity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,16 @@
import java.util.Optional;
import java.util.stream.Collectors;

import static io.ballerina.stdlib.http.compiler.Constants.ALLOWED_RETURN_UNION;
import static io.ballerina.stdlib.http.compiler.Constants.BALLERINA;
import static io.ballerina.stdlib.http.compiler.Constants.CALLER_ANNOTATION_TYPE;
import static io.ballerina.stdlib.http.compiler.Constants.CALLER_OBJ_NAME;
import static io.ballerina.stdlib.http.compiler.Constants.HEADER_ANNOTATION_TYPE;
import static io.ballerina.stdlib.http.compiler.Constants.HEADER_OBJ_NAME;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_102;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_103;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_104;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_105;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_106;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_107;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_108;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_109;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_110;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_111;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_112;
import static io.ballerina.stdlib.http.compiler.Constants.HTTP_113;
import static io.ballerina.stdlib.http.compiler.Constants.PAYLOAD_ANNOTATION_TYPE;
import static io.ballerina.stdlib.http.compiler.Constants.REQUEST_OBJ_NAME;
import static io.ballerina.stdlib.http.compiler.Constants.RESOURCE_CONFIG_ANNOTATION;
import static io.ballerina.stdlib.http.compiler.Constants.RESPONSE_OBJ_NAME;
import static io.ballerina.tools.diagnostics.DiagnosticSeverity.ERROR;

/**
* Validates a ballerina http resource.
Expand Down Expand Up @@ -109,9 +95,12 @@ private static void extractInputParamTypeAndValidate(SyntaxNodeAnalysisContext c
if (resourceMethodSymbolOptional.isEmpty()) {
return;
}
List<ParameterSymbol> parameters =
((ResourceMethodSymbol) resourceMethodSymbolOptional.get()).typeDescriptor().parameters();
for (ParameterSymbol param : parameters) {
Optional<List<ParameterSymbol>> parametersOptional =
((ResourceMethodSymbol) resourceMethodSymbolOptional.get()).typeDescriptor().params();
if (parametersOptional.isEmpty()) {
return;
}
for (ParameterSymbol param : parametersOptional.get()) {
String paramType = param.typeDescriptor().signature();
Optional<String> nameOptional = param.getName();
String paramName = nameOptional.isEmpty() ? "" : nameOptional.get();
Expand Down Expand Up @@ -156,16 +145,13 @@ private static void extractInputParamTypeAndValidate(SyntaxNodeAnalysisContext c
reportInvalidParameterType(ctx, member, paramType);
}

} else if (kind == TypeDescKind.STRING || kind == TypeDescKind.INT || kind == TypeDescKind.FLOAT ||
kind == TypeDescKind.DECIMAL || kind == TypeDescKind.BOOLEAN) {
} else if (isAllowedQueryParamType(kind)) {
// Allowed query param types
} else if (kind == TypeDescKind.ARRAY) {
// Allowed query param array types
TypeSymbol arrTypeSymbol = ((ArrayTypeSymbol) typeSymbol).memberTypeDescriptor();
TypeDescKind elementKind = arrTypeSymbol.typeKind();
if (elementKind == TypeDescKind.STRING || elementKind == TypeDescKind.INT ||
elementKind == TypeDescKind.FLOAT || elementKind == TypeDescKind.DECIMAL ||
elementKind == TypeDescKind.BOOLEAN) {
if (isAllowedQueryParamType(elementKind)) {
continue;
}
} else if (kind == TypeDescKind.UNION) {
Expand All @@ -185,14 +171,14 @@ private static void extractInputParamTypeAndValidate(SyntaxNodeAnalysisContext c
if (elementKind == TypeDescKind.ARRAY) {
TypeSymbol arrTypeSymbol = ((ArrayTypeSymbol) type).memberTypeDescriptor();
TypeDescKind arrElementKind = arrTypeSymbol.typeKind();
if (arrElementKind != TypeDescKind.STRING && arrElementKind != TypeDescKind.INT &&
arrElementKind != TypeDescKind.FLOAT && arrElementKind != TypeDescKind.DECIMAL &&
arrElementKind != TypeDescKind.BOOLEAN) {
reportInvalidQueryParameterType(ctx, member, paramName);
if (isAllowedQueryParamType(arrElementKind)) {
continue;
}
reportInvalidQueryParameterType(ctx, member, paramName);
} else {
if (elementKind == TypeDescKind.NIL || isAllowedQueryParamType(elementKind)) {
continue;
}
} else if (elementKind != TypeDescKind.NIL && elementKind != TypeDescKind.STRING &&
elementKind != TypeDescKind.INT && elementKind != TypeDescKind.FLOAT &&
elementKind != TypeDescKind.DECIMAL && elementKind != TypeDescKind.BOOLEAN) {
reportInvalidQueryParameterType(ctx, member, paramName);
}
}
Expand Down Expand Up @@ -366,6 +352,11 @@ private static void extractInputParamTypeAndValidate(SyntaxNodeAnalysisContext c
}
}

private static boolean isAllowedQueryParamType(TypeDescKind kind) {
return kind == TypeDescKind.STRING || kind == TypeDescKind.INT || kind == TypeDescKind.FLOAT ||
kind == TypeDescKind.DECIMAL || kind == TypeDescKind.BOOLEAN;
}

private static void extractReturnTypeAndValidate(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode member) {
Optional<ReturnTypeDescriptorNode> returnTypeDescriptorNode = member.functionSignature().returnTypeDesc();
if (returnTypeDescriptorNode.isEmpty()) {
Expand Down Expand Up @@ -478,87 +469,72 @@ private static boolean isHttpModuleType(String expectedType, TypeSymbol typeDesc

private static void reportInvalidReturnType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String returnType) {
String msg = "invalid resource method return type: expected '" + ALLOWED_RETURN_UNION +
"', but found '" + returnType + "'";
reportError(ctx, node, msg, HTTP_102);
updateDiagnostic(ctx, node, returnType, HttpDiagnosticCodes.HTTP_102);
}

private static void reportInvalidResourceAnnotation(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String annotName) {
String msg = "invalid resource method annotation type: expected 'http:" + RESOURCE_CONFIG_ANNOTATION + "', " +
"but found '" + annotName + "'";
reportError(ctx, node, msg, HTTP_103);
updateDiagnostic(ctx, node, annotName, HttpDiagnosticCodes.HTTP_103);
}

private static void reportInvalidParameterAnnotation(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid annotation type on param '" + paramName +
"': expected one of the following types: 'http:Payload', 'http:CallerInfo', 'http:Headers'";
reportError(ctx, node, msg, HTTP_104);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_104);
}

private static void reportInvalidParameter(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid resource parameter" + (paramName.isEmpty() ? "" : ": '" + paramName + "'");
reportError(ctx, node, msg, HTTP_105);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_105);
}

private static void reportInvalidParameterType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String typeName) {
String msg = "invalid resource parameter type: '" + typeName + "'";
reportError(ctx, node, msg, HTTP_106);
updateDiagnostic(ctx, node, typeName, HttpDiagnosticCodes.HTTP_106);
}

private static void reportInvalidPayloadParameterType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String typeName) {
String msg = "invalid payload parameter type: '" + typeName + "'";
reportError(ctx, node, msg, HTTP_107);
updateDiagnostic(ctx, node, typeName, HttpDiagnosticCodes.HTTP_107);
}

private static void reportInvalidMultipleAnnotation(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid multiple resource parameter annotations for '" + paramName +
"': expected one of the following types: 'http:Payload', 'http:CallerInfo', 'http:Headers'";
reportError(ctx, node, msg, HTTP_108);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_108);
}

private static void reportInvalidHeaderParameterType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid type of header param '" + paramName + "': expected 'string' or 'string[]'";
reportError(ctx, node, msg, HTTP_109);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_109);
}

private static void reportInvalidUnionHeaderType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid union type of header param '" + paramName + "': a string or an array of a string can " +
"only be union with '()'. Eg: string|() or string[]|()";
reportError(ctx, node, msg, HTTP_110);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_110);
}

private static void reportInvalidCallerParameterType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid type of caller param '" + paramName + "': expected 'http:Caller'";
reportError(ctx, node, msg, HTTP_111);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_111);
}

private static void reportInvalidQueryParameterType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid type of query param '" + paramName + "': expected one of the 'string', 'int', 'float', " +
"'boolean', 'decimal' types or the array types of them";
reportError(ctx, node, msg, HTTP_112);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_112);
}

private static void reportInvalidUnionQueryType(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String paramName) {
String msg = "invalid union type of query param '" + paramName + "': 'string', 'int', 'float', 'boolean', " +
"'decimal' type or the array types of them can only be union with '()'. Eg: string? or int[]?";
reportError(ctx, node, msg, HTTP_113);
updateDiagnostic(ctx, node, paramName, HttpDiagnosticCodes.HTTP_113);
}

private static void updateDiagnostic(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node, String returnType,
HttpDiagnosticCodes httpDiagnosticCodes) {
DiagnosticInfo diagnosticInfo = getDiagnosticInfo(httpDiagnosticCodes, returnType);
ctx.reportDiagnostic(DiagnosticFactory.createDiagnostic(diagnosticInfo, node.location()));
}

private static void reportError(SyntaxNodeAnalysisContext ctx, FunctionDefinitionNode node,
String errorMsg, String errorCode) {
DiagnosticInfo diagnosticInfo = new DiagnosticInfo(errorCode, errorMsg, ERROR);
ctx.reportDiagnostic(
DiagnosticFactory.createDiagnostic(diagnosticInfo, node.location(), node.functionName().toString()));
private static DiagnosticInfo getDiagnosticInfo(HttpDiagnosticCodes diagnostic, Object... args) {
return new DiagnosticInfo(diagnostic.getCode(), String.format(diagnostic.getMessage(), args),
diagnostic.getSeverity());
}
}
Loading

0 comments on commit cb735d1

Please sign in to comment.