Skip to content

Commit

Permalink
Merge pull request #874 from aashikam/annotation-fix
Browse files Browse the repository at this point in the history
[7.x] Update compiler plugin to allow annotations
  • Loading branch information
aashikam authored Aug 21, 2023
2 parents cc8edaa + b4ea674 commit 0acee56
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 54 deletions.
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerinax"
name = "rabbitmq"
version = "2.9.0"
version = "2.9.1"
authors = ["Ballerina"]
keywords = ["service", "client", "messaging", "network", "pubsub"]
repository = "https://github.com/ballerina-platform/module-ballerinax-rabbitmq"
Expand All @@ -18,8 +18,8 @@ path = "./lib/amqp-client-5.10.0.jar"
[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "rabbitmq-native"
version = "2.9.0"
path = "../native/build/libs/rabbitmq-native-2.9.0.jar"
version = "2.9.1"
path = "../native/build/libs/rabbitmq-native-2.9.1-SNAPSHOT.jar"

[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/CompilerPlugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ id = "rabbitmq-compiler-plugin"
class = "io.ballerina.stdlib.rabbitmq.plugin.RabbitmqCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/rabbitmq-compiler-plugin-2.9.0.jar"
path = "../compiler-plugin/build/libs/rabbitmq-compiler-plugin-2.9.1-SNAPSHOT.jar"
8 changes: 4 additions & 4 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ modules = [
[[package]]
org = "ballerina"
name = "file"
version = "1.8.0"
version = "1.8.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "io"},
Expand All @@ -71,7 +71,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
version = "2.9.0"
version = "2.9.2"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
Expand Down Expand Up @@ -240,7 +240,7 @@ modules = [
[[package]]
org = "ballerina"
name = "log"
version = "2.8.0"
version = "2.8.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "io"},
Expand Down Expand Up @@ -386,7 +386,7 @@ modules = [
[[package]]
org = "ballerinax"
name = "rabbitmq"
version = "2.9.0"
version = "2.9.1"
dependencies = [
{org = "ballerina", name = "constraint"},
{org = "ballerina", name = "crypto"},
Expand Down
8 changes: 7 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ This file contains all the notable changes done to the Ballerina RabbitMQ packag

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[Unreleased]
## Unreleased

### Changed

- [[#4734] Changed disallowing service level annotations in the compiler plugin](https://github.com/ballerina-platform/ballerina-standard-library/issues/4734)

## [2.7.0] - 2023-04-10

### Changed
- [[#4237] Exit the Listener When Panic Occurred](https://github.com/ballerina-platform/ballerina-standard-library/issues/4237)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private CodeActionInfo getExpectedCodeAction(String filePath, int line, int offs
LinePosition.from(line, offset));
CodeActionArgument locationArg = CodeActionArgument.from(NODE_LOCATION, lineRange);
CodeActionInfo codeAction = CodeActionInfo.from("Insert service template", List.of(locationArg));
codeAction.setProviderName("RABBITMQ_123/ballerinax/rabbitmq/ADD_REMOTE_FUNCTION_CODE_SNIPPET");
codeAction.setProviderName("RABBITMQ_121/ballerinax/rabbitmq/ADD_REMOTE_FUNCTION_CODE_SNIPPET");
return codeAction;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.INVALID_RETURN_TYPE_ERROR_OR_NIL;
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.MUST_HAVE_MESSAGE;
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.MUST_HAVE_MESSAGE_AND_ERROR;
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.NO_ANNOTATION;
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.NO_ON_MESSAGE_OR_ON_REQUEST;
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.ONLY_PARAMS_ALLOWED;
import static io.ballerina.stdlib.rabbitmq.plugin.PluginConstants.CompilationErrors.ONLY_PARAMS_ALLOWED_ON_ERROR;
Expand Down Expand Up @@ -127,6 +128,14 @@ public void testValidService9() {
Assert.assertEquals(diagnosticResult.errorCount(), 0);
}

@Test(description = "Validate `rabbitmq:Service` with `display` annotation")
public void testValidService10() {
Package currentPackage = loadPackage("valid_service_10");
PackageCompilation compilation = currentPackage.getCompilation();
DiagnosticResult diagnosticResult = compilation.diagnosticResult();
Assert.assertEquals(diagnosticResult.errorCount(), 0);
}

@Test
public void testInvalidService1() {
Package currentPackage = loadPackage("invalid_service_1");
Expand Down Expand Up @@ -379,6 +388,16 @@ public void testInvalidService21() {
}
}

@Test(description = "Validate `rabbitmq:Service` no service name or service config annotation")
public void testInvalidService22() {
Package currentPackage = loadPackage("invalid_service_22");
PackageCompilation compilation = currentPackage.getCompilation();
DiagnosticResult diagnosticResult = compilation.diagnosticResult();
Assert.assertEquals(diagnosticResult.errorCount(), 1);
Diagnostic diagnostic = (Diagnostic) diagnosticResult.errors().toArray()[0];
assertDiagnostic(diagnostic, NO_ANNOTATION);
}

private Package loadPackage(String path) {
Path projectDirPath = RESOURCE_DIRECTORY.resolve(BALLERINA_SOURCES).resolve(path);
BuildProject project = BuildProject.load(getEnvironmentBuilder(), projectDirPath);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "rabbitmq_test"
name = "invalid_service_22"
version = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
//
// WSO2 LLC. 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.

import ballerinax/rabbitmq;

listener rabbitmq:Listener channelListener =
new(rabbitmq:DEFAULT_HOST, rabbitmq:DEFAULT_PORT);

@display {
label: "rabbitmqService"
}
service rabbitmq:Service on channelListener {
remote function onMessage(rabbitmq:Message message) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "rabbitmq_test"
name = "valid_service_10"
version = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
//
// WSO2 LLC. 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.

import ballerinax/rabbitmq;

listener rabbitmq:Listener channelListener =
new(rabbitmq:DEFAULT_HOST, rabbitmq:DEFAULT_PORT);

@display {
label: "rabbitmqService"
}
@rabbitmq:ServiceConfig {
queueName: "MyQueue"
}
service rabbitmq:Service on channelListener {
remote function onMessage(rabbitmq:Message message) returns error? {
}
}

@display {
label: "natsService"
}
service "MyQueue" on channelListener {
remote function onMessage(rabbitmq:Message message) returns error? {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,10 @@ enum CompilationErrors {
"RABBITMQ_117"),
INVALID_MULTIPLE_LISTENERS("Multiple listener attachments. Only one rabbitmq:Listener is allowed.",
"RABBITMQ_118"),
INVALID_ANNOTATION_NUMBER("Only one service config annotation is allowed.",
"RABBITMQ_119"),
NO_ANNOTATION("No @rabbitmq:ServiceConfig{} annotation is found.",
"RABBITMQ_120"),
INVALID_ANNOTATION("Invalid service config annotation. Only @rabbitmq:ServiceConfig{} is allowed.",
"RABBITMQ_121"),
NO_ANNOTATION("No ServiceConfig annotation is found.", "RABBITMQ_119"),
INVALID_SERVICE_ATTACH_POINT("Invalid service attach point. Only string literals are allowed.",
"RABBITMQ_122"),
TEMPLATE_CODE_GENERATION_HINT("Template generation for empty service", "RABBITMQ_123");
"RABBITMQ_120"),
TEMPLATE_CODE_GENERATION_HINT("Template generation for empty service", "RABBITMQ_121");

private final String error;
private final String errorCode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import io.ballerina.tools.diagnostics.DiagnosticFactory;
import io.ballerina.tools.diagnostics.DiagnosticInfo;
import io.ballerina.tools.diagnostics.DiagnosticSeverity;
import io.ballerina.tools.diagnostics.Location;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -97,47 +96,41 @@ private void validateAttachPoint(SyntaxNodeAnalysisContext context) {
SemanticModel semanticModel = context.semanticModel();
ServiceDeclarationNode serviceDeclarationNode = (ServiceDeclarationNode) context.node();
Optional<Symbol> symbol = semanticModel.symbol(serviceDeclarationNode);

if (symbol.isPresent()) {
ServiceDeclarationSymbol serviceDeclarationSymbol = (ServiceDeclarationSymbol) symbol.get();
Optional<ServiceAttachPoint> attachPoint = serviceDeclarationSymbol.attachPoint();
List<AnnotationSymbol> symbolList = serviceDeclarationSymbol.annotations();
if (attachPoint.isEmpty()) {
if (symbolList.isEmpty()) {
context.reportDiagnostic(PluginUtils.getDiagnostic(CompilationErrors.NO_ANNOTATION,
DiagnosticSeverity.ERROR, serviceDeclarationNode.location()));
} else if (symbolList.size() > 1) {
context.reportDiagnostic(PluginUtils.getDiagnostic(CompilationErrors.INVALID_ANNOTATION_NUMBER,
DiagnosticSeverity.ERROR, serviceDeclarationNode.location()));
} else {
validateAnnotation(symbolList.get(0), serviceDeclarationNode.location(), context);
}
} else {
if (attachPoint.get().kind() != ServiceAttachPointKind.STRING_LITERAL) {
if (serviceDeclarationSymbol.annotations().isEmpty()) {
context.reportDiagnostic(PluginUtils.getDiagnostic(
CompilationErrors.INVALID_SERVICE_ATTACH_POINT,
DiagnosticSeverity.ERROR, serviceDeclarationNode.location()));
} else {
validateAnnotation(symbolList.get(0), serviceDeclarationNode.location(), context);
}
}
Optional<ServiceAttachPoint> serviceNameAttachPoint = serviceDeclarationSymbol.attachPoint();
List<AnnotationSymbol> annotations = serviceDeclarationSymbol.annotations();

boolean serviceNameIsStringLiteral = serviceNameAttachPoint.isPresent() &&
serviceNameAttachPoint.get().kind() == ServiceAttachPointKind.STRING_LITERAL;

if (annotations.isEmpty() && !serviceNameIsStringLiteral) {
// Case 1: No service name and no annotation
reportError(context, CompilationErrors.INVALID_SERVICE_ATTACH_POINT, serviceDeclarationNode);
} else if (!hasServiceConfig(annotations) && !serviceNameIsStringLiteral) {
// Case 2: Service name is not a string and no annotation
reportError(context, CompilationErrors.NO_ANNOTATION, serviceDeclarationNode);
}
}
}

private void validateAnnotation(AnnotationSymbol annotationSymbol, Location location,
SyntaxNodeAnalysisContext context) {
Optional<ModuleSymbol> moduleSymbolOptional = annotationSymbol.getModule();
if (moduleSymbolOptional.isEmpty()) {
context.reportDiagnostic(PluginUtils.getDiagnostic(CompilationErrors.INVALID_ANNOTATION,
DiagnosticSeverity.ERROR, location));
} else {
ModuleSymbol moduleSymbol = moduleSymbolOptional.get();
if (!moduleSymbol.id().orgName().equals(PluginConstants.PACKAGE_ORG) ||
!moduleSymbol.id().moduleName().equals(PluginConstants.PACKAGE_PREFIX)) {
context.reportDiagnostic(PluginUtils.getDiagnostic(CompilationErrors.INVALID_ANNOTATION,
DiagnosticSeverity.ERROR, location));
private void reportError(SyntaxNodeAnalysisContext context, CompilationErrors error, Node locationNode) {
context.reportDiagnostic(PluginUtils.getDiagnostic(error, DiagnosticSeverity.ERROR, locationNode.location()));
}

private boolean hasServiceConfig(List<AnnotationSymbol> annotationSymbols) {
for (AnnotationSymbol annotationSymbol : annotationSymbols) {
Optional<ModuleSymbol> moduleSymbolOptional = annotationSymbol.getModule();
if (moduleSymbolOptional.isPresent()) {
ModuleSymbol moduleSymbol = moduleSymbolOptional.get();
if (PluginConstants.PACKAGE_ORG.equals(moduleSymbol.id().orgName()) &&
PluginConstants.PACKAGE_PREFIX.equals(moduleSymbol.id().moduleName())) {
// not checking name as rabbitmq has only two annotations and only one is allowed on services.
return true;
}
}
}
return false;
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
org.gradle.caching=true
group=io.ballerina.stdlib
version=2.9.0
version=2.9.1-SNAPSHOT
ballerinaLangVersion= 2201.7.0

amqpClientVersion=5.10.0
Expand Down

0 comments on commit 0acee56

Please sign in to comment.