-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #58 from poorna2152/service_restrict
Disallow service declarations and dynamic service register when connector imported
- Loading branch information
Showing
7 changed files
with
354 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
...plugin/src/main/java/io/ballerina/stdlib/mi/plugin/ListenerAndServiceDefAnalysisTask.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). | ||
* | ||
* 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. | ||
*/ | ||
|
||
package io.ballerina.stdlib.mi.plugin; | ||
|
||
import io.ballerina.compiler.syntax.tree.Node; | ||
import io.ballerina.compiler.syntax.tree.SyntaxKind; | ||
import io.ballerina.projects.plugins.AnalysisTask; | ||
import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext; | ||
import io.ballerina.tools.diagnostics.DiagnosticFactory; | ||
import io.ballerina.tools.diagnostics.DiagnosticInfo; | ||
import io.ballerina.tools.diagnostics.DiagnosticSeverity; | ||
|
||
/** | ||
* Analysis task that emit error diagnostic for service and listener declarations found in the code. | ||
* | ||
* @since 0.1.3 | ||
*/ | ||
public class ListenerAndServiceDefAnalysisTask implements AnalysisTask<SyntaxNodeAnalysisContext> { | ||
|
||
@Override | ||
public void perform(SyntaxNodeAnalysisContext context) { | ||
DiagnosticErrorCode diagnosticCode; | ||
Node node = context.node(); | ||
if (node.kind() == SyntaxKind.SERVICE_DECLARATION) { | ||
diagnosticCode = DiagnosticErrorCode.SERVICE_DEF_NOT_ALLOWED; | ||
} else { | ||
diagnosticCode = DiagnosticErrorCode.LISTENER_DECLARATION_NOT_ALLOWED; | ||
} | ||
DiagnosticInfo diagnosticInfo = | ||
new DiagnosticInfo(diagnosticCode.diagnosticId(), diagnosticCode.message(), DiagnosticSeverity.ERROR); | ||
context.reportDiagnostic(DiagnosticFactory.createDiagnostic(diagnosticInfo, node.location())); | ||
} | ||
} |
113 changes: 113 additions & 0 deletions
113
...r-plugin/src/main/java/io/ballerina/stdlib/mi/plugin/VariableDeclarationAnalysisTask.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). | ||
* | ||
* 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. | ||
*/ | ||
|
||
package io.ballerina.stdlib.mi.plugin; | ||
|
||
import io.ballerina.compiler.api.impl.symbols.BallerinaUnionTypeSymbol; | ||
import io.ballerina.compiler.api.symbols.IntersectionTypeSymbol; | ||
import io.ballerina.compiler.api.symbols.ObjectTypeSymbol; | ||
import io.ballerina.compiler.api.symbols.Symbol; | ||
import io.ballerina.compiler.api.symbols.TypeDescKind; | ||
import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; | ||
import io.ballerina.compiler.api.symbols.TypeSymbol; | ||
import io.ballerina.compiler.api.symbols.VariableSymbol; | ||
import io.ballerina.compiler.syntax.tree.Node; | ||
import io.ballerina.projects.plugins.AnalysisTask; | ||
import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext; | ||
import io.ballerina.tools.diagnostics.DiagnosticFactory; | ||
import io.ballerina.tools.diagnostics.DiagnosticInfo; | ||
import io.ballerina.tools.diagnostics.DiagnosticSeverity; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
/** | ||
* Analysis task that emits error diagnostics for local and module-level variable declarations with a type that match | ||
* the shape of the `Listener` type found in the code. | ||
* | ||
* @since 0.1.3 | ||
*/ | ||
public class VariableDeclarationAnalysisTask implements AnalysisTask<SyntaxNodeAnalysisContext> { | ||
|
||
private final List<String> methods = List.of("start", "gracefulStop", "immediateStop", "attach", "detach"); | ||
|
||
@Override | ||
public void perform(SyntaxNodeAnalysisContext context) { | ||
Node node = context.node(); | ||
Optional<Symbol> symbol = context.semanticModel().symbol(node); | ||
if (symbol.isEmpty() || !(symbol.get() instanceof VariableSymbol)) { | ||
return; | ||
} | ||
|
||
TypeSymbol typeSymbol = getRawType(((VariableSymbol) symbol.get()).typeDescriptor()); | ||
List<ObjectTypeSymbol> objectTypeSymbols = new ArrayList<>(); | ||
TypeDescKind typeDescKind = typeSymbol.typeKind(); | ||
if (typeDescKind == TypeDescKind.UNION) { | ||
objectTypeSymbols = getObjectTypeMembers((BallerinaUnionTypeSymbol) typeSymbol); | ||
} else if (typeDescKind == TypeDescKind.OBJECT) { | ||
objectTypeSymbols.add((ObjectTypeSymbol) typeSymbol); | ||
} | ||
|
||
for (ObjectTypeSymbol objectTypeSymbol : objectTypeSymbols) { | ||
List<String> classMethods = objectTypeSymbol.methods().keySet().stream().toList(); | ||
if (!classMethods.containsAll(methods)) { | ||
continue; | ||
} | ||
DiagnosticErrorCode diagnosticCode = DiagnosticErrorCode.LISTENER_SHAPE_VAR_NOT_ALLOWED; | ||
DiagnosticInfo diagnosticInfo = | ||
new DiagnosticInfo(diagnosticCode.diagnosticId(), diagnosticCode.message(), | ||
DiagnosticSeverity.ERROR); | ||
context.reportDiagnostic(DiagnosticFactory.createDiagnostic(diagnosticInfo, node.location())); | ||
return; | ||
} | ||
} | ||
|
||
private TypeSymbol getRawType(TypeSymbol typeDescriptor) { | ||
TypeDescKind typeDescKind = typeDescriptor.typeKind(); | ||
if (typeDescKind == TypeDescKind.INTERSECTION) { | ||
return getRawType(((IntersectionTypeSymbol) typeDescriptor).effectiveTypeDescriptor()); | ||
} | ||
if (typeDescKind == TypeDescKind.TYPE_REFERENCE) { | ||
TypeSymbol typeSymbol = ((TypeReferenceTypeSymbol) typeDescriptor).typeDescriptor(); | ||
TypeDescKind refTypeDescKind = typeSymbol.typeKind(); | ||
if (refTypeDescKind == TypeDescKind.INTERSECTION) { | ||
return getRawType(((IntersectionTypeSymbol) typeSymbol).effectiveTypeDescriptor()); | ||
} | ||
if (refTypeDescKind == TypeDescKind.TYPE_REFERENCE) { | ||
return getRawType(typeSymbol); | ||
} | ||
return typeSymbol; | ||
} | ||
return typeDescriptor; | ||
} | ||
|
||
private List<ObjectTypeSymbol> getObjectTypeMembers(BallerinaUnionTypeSymbol unionTypeSymbol) { | ||
ArrayList<ObjectTypeSymbol> objectTypes = new ArrayList<>(); | ||
for (TypeSymbol member : unionTypeSymbol.memberTypeDescriptors()) { | ||
member = getRawType(member); | ||
TypeDescKind typeDescKind = member.typeKind(); | ||
if (typeDescKind == TypeDescKind.OBJECT) { | ||
objectTypes.add((ObjectTypeSymbol) member); | ||
} else if (typeDescKind == TypeDescKind.UNION) { | ||
objectTypes.addAll(getObjectTypeMembers((BallerinaUnionTypeSymbol) member)); | ||
} | ||
} | ||
return objectTypes; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
tests/src/test/resources/ballerina/project5/Ballerina.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
org = "testOrg" | ||
name = "project5" | ||
version = "1.0.0" | ||
distribution = "2201.9.2" | ||
|
||
[build-options] | ||
observabilityIncluded = true | ||
|
||
[[dependency]] | ||
org = "ballerinax" | ||
name = "mi" | ||
version = "0.1.2" | ||
repository = "local" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). | ||
// | ||
// 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 ballerina/graphql; | ||
import ballerina/http; | ||
import ballerina/lang.runtime; | ||
import ballerinax/mi; | ||
|
||
service / on new http:Listener(9090) { | ||
resource function get greeting() returns string { | ||
return "ballerina mi connector http service!"; | ||
} | ||
} | ||
|
||
service /graphql on new graphql:Listener(9091) { | ||
resource function get greeting() returns string { | ||
return "ballerina mi connector graphql service"; | ||
} | ||
} | ||
|
||
service class EchoService { | ||
remote function greeting() returns string { | ||
return "hello"; | ||
} | ||
} | ||
|
||
listener http:Listener httpListener = check new (9090); | ||
http:Listener httpListener2 = check new (9091); | ||
|
||
http:Service helloService = service object { | ||
resource function get greeting() returns string { | ||
return "dynamic listener!"; | ||
} | ||
}; | ||
|
||
var obj1 = object { | ||
public function 'start() returns error? { | ||
} | ||
|
||
public function gracefulStop() returns error? { | ||
} | ||
|
||
public function immediateStop() returns error? { | ||
} | ||
|
||
public function attach() returns error? { | ||
} | ||
|
||
public function detach() returns error? { | ||
} | ||
}; | ||
|
||
|
||
var obj2 = object { | ||
public function 'start() returns error? { | ||
} | ||
|
||
public function gracefulStop() returns error? { | ||
} | ||
|
||
}; | ||
|
||
var obj3 = object { | ||
public function 'start() returns error? { | ||
} | ||
|
||
public function gracefulStop() returns error? { | ||
} | ||
|
||
public function immediateStop() returns error? { | ||
} | ||
|
||
public function attach() returns error? { | ||
} | ||
|
||
public function detach() returns error? { | ||
} | ||
|
||
public function bar() { | ||
|
||
} | ||
}; | ||
|
||
class ListenerClass { | ||
public function 'start() returns error? { | ||
} | ||
|
||
public function gracefulStop() returns error? { | ||
} | ||
|
||
public function immediateStop() returns error? { | ||
} | ||
|
||
public function attach() returns error? { | ||
} | ||
|
||
public function detach() returns error? { | ||
} | ||
} | ||
|
||
@mi:ConnectorInfo { | ||
} | ||
function registerServiceDynamically() { | ||
http:Listener|error? httpListener3 = new (9092); | ||
error? e = httpListener2.attach(helloService, "foo/bar"); | ||
e = httpListener2.'start(); | ||
runtime:registerListener(httpListener2); | ||
ListenerClass cls = new(); | ||
} |