Skip to content

Commit

Permalink
Merge pull request #770 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 9cbba62 + 78664fa commit 536fa82
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 55 deletions.
2 changes: 1 addition & 1 deletion ballerina-tests/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[package]
org = "ballerinax"
name = "nats_tests"
version = "2.9.0"
version = "2.9.1"
6 changes: 3 additions & 3 deletions ballerina-tests/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "log"
version = "2.8.0"
version = "2.8.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "io"},
Expand Down Expand Up @@ -144,7 +144,7 @@ dependencies = [
[[package]]
org = "ballerinax"
name = "nats"
version = "2.9.0"
version = "2.9.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "crypto"},
Expand All @@ -158,7 +158,7 @@ modules = [
[[package]]
org = "ballerinax"
name = "nats_tests"
version = "2.9.0"
version = "2.9.1"
dependencies = [
{org = "ballerina", name = "lang.runtime"},
{org = "ballerina", name = "lang.string"},
Expand Down
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 = "nats"
version = "2.9.0"
version = "2.9.1"
authors = ["Ballerina"]
keywords = ["service", "client", "messaging", "network", "pubsub"]
repository = "https://github.com/ballerina-platform/module-ballerinax-nats"
Expand All @@ -18,8 +18,8 @@ path = "./lib/jnats-2.16.0.jar"
[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "nats-native"
version = "2.9.0"
path = "../native/build/libs/nats-native-2.9.0.jar"
version = "2.9.1"
path = "../native/build/libs/nats-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 = "nats-compiler-plugin"
class = "io.ballerina.stdlib.nats.plugin.NatsCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/nats-compiler-plugin-2.9.0.jar"
path = "../compiler-plugin/build/libs/nats-compiler-plugin-2.9.1-SNAPSHOT.jar"
4 changes: 2 additions & 2 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "log"
version = "2.8.0"
version = "2.8.1"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "io"},
Expand Down Expand Up @@ -160,7 +160,7 @@ modules = [
[[package]]
org = "ballerinax"
name = "nats"
version = "2.9.0"
version = "2.9.1"
dependencies = [
{org = "ballerina", name = "constraint"},
{org = "ballerina", name = "crypto"},
Expand Down
9 changes: 7 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# Change Log
This file contains all the notable changes done to the Ballerina NATS package through the releases.

[Unreleased]
## Unreleased

### Changed
- [[#4237] Exit the Listener When Panic Occurred](https://github.com/ballerina-platform/ballerina-standard-library/issues/4237)

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

## [2.7.0] - 2023-04-10

### Changed
- [[#4237] Exit the Listener When Panic Occurred](https://github.com/ballerina-platform/ballerina-standard-library/issues/4237)

## [2.6.0] - 2023-02-20

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("NATS_121/ballerinax/nats/ADD_REMOTE_FUNCTION_CODE_SNIPPET");
codeAction.setProviderName("NATS_119/ballerinax/nats/ADD_REMOTE_FUNCTION_CODE_SNIPPET");
return codeAction;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ public void testValidJetStreamServiceWithReadOnlyMessage() {
Assert.assertEquals(diagnosticResult.errors().size(), 0);
}

@Test
public void testValidServicesWithDisplayAnnotation() {
Package currentPackage = loadPackage("valid_service_23");
PackageCompilation compilation = currentPackage.getCompilation();
DiagnosticResult diagnosticResult = compilation.diagnosticResult();
Assert.assertEquals(diagnosticResult.errors().size(), 0);
}

@Test
public void testInvalidService1() {
Package currentPackage = loadPackage("invalid_service_1");
Expand Down Expand Up @@ -523,6 +531,16 @@ public void testJetStreamServiceWithInvalidReturnOnMessageMethod() {
assertDiagnostic(diagnostic, CompilationErrors.INVALID_RETURN_TYPE_ERROR_OR_NIL);
}

@Test(description = "NATS service with no service config or service name")
public void testInvalidService30() {
Package currentPackage = loadPackage("invalid_service_30");
PackageCompilation compilation = currentPackage.getCompilation();
DiagnosticResult diagnosticResult = compilation.diagnosticResult();
Assert.assertEquals(diagnosticResult.errors().size(), 1);
Diagnostic diagnostic = (Diagnostic) diagnosticResult.errors().toArray()[0];
assertDiagnostic(diagnostic, CompilationErrors.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 = "nats_test"
name = "invalid_service_30"
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/nats;

listener nats:Listener subscription = new(nats:DEFAULT_URL);

@display {
label: "natsService"
}
service nats:Service on subscription {

remote function onMessage(nats:Message message) returns error? {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "nats_test"
name = "valid_service_23"
version = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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/nats;

listener nats:Listener subscription = new(nats:DEFAULT_URL);

@display {
label: "natsService"
}
service "demo.bbe" on subscription {

remote function onMessage(nats:Message message) {
}
}

@display {
label: "natsService"
}
@nats:ServiceConfig {
subject: "demo.bbe.*"
}
service nats:Service on subscription {

remote function onMessage(nats:Message message) {
}
}

nats:Client natsClient = check new(nats:DEFAULT_URL);
listener nats:JetStreamListener streamSubscription = new(natsClient);

@display {
label: "natsService"
}
@nats:StreamServiceConfig {
subject: "demo.bbe.*"
}
service nats:JetStreamService on streamSubscription {

remote function onMessage(readonly & nats:JetStreamMessage message) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext;
import io.ballerina.stdlib.nats.plugin.PluginConstants.CompilationErrors;
import io.ballerina.tools.diagnostics.DiagnosticSeverity;
import io.ballerina.tools.diagnostics.Location;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -93,44 +92,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();
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,10 @@ enum CompilationErrors {
"NATS_115"),
INVALID_MULTIPLE_LISTENERS("Multiple listener attachments. Only one nats:Listener is allowed.",
"NATS_116"),
INVALID_ANNOTATION_NUMBER("Only one service config annotation is allowed.",
"NATS_117"),
NO_ANNOTATION("No @nats:ServiceConfig{} annotation is found.",
"NATS_118"),
INVALID_ANNOTATION("Invalid service config annotation. Only @nats:ServiceConfig{} is allowed.",
"NATS_119"),
NO_ANNOTATION("No ServiceConfig annotation is found.", "NATS_117"),
INVALID_SERVICE_ATTACH_POINT("Invalid service attach point. Only string literals are allowed.",
"NATS_120"),
TEMPLATE_CODE_GENERATION_HINT("Template generation for empty service", "NATS_121");
"NATS_118"),
TEMPLATE_CODE_GENERATION_HINT("Template generation for empty service", "NATS_119");

private final String error;
private final String errorCode;
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
org.gradle.caching=true
group=io.ballerina.stdlib

version=2.9.0
version=2.9.1-SNAPSHOT
ballerinaLangVersion= 2201.7.0
ballerinaGradlePluginVersion=1.1.0

Expand Down

0 comments on commit 536fa82

Please sign in to comment.