Skip to content

Commit

Permalink
Add inital impl
Browse files Browse the repository at this point in the history
  • Loading branch information
LakshanWeerasinghe committed Mar 4, 2025
1 parent ec7850f commit 26d7ae7
Show file tree
Hide file tree
Showing 20 changed files with 1,614 additions and 29 deletions.
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=org.ballerinalang
version=2.0.0-SNAPSHOT
version=2.0.0
ballerinaLangVersion=2201.12.0-20250228-201300-8d411a0f

ballerinaGradlePluginVersion=2.3.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class FunctionData {
private final boolean returnError;
private final boolean inferredReturnType;
private Map<String, ParameterData> parameters;
private String packageId;

public FunctionData(int functionId, String name, String description, String returnType,
String packageName, String org, String version, String resourcePath,
Expand All @@ -60,6 +61,10 @@ public void setParameters(Map<String, ParameterData> parameters) {
this.parameters = parameters;
}

public void setPackageId(String attachmentId) {
this.packageId = attachmentId;
}

// Getters
public int functionId() {
return functionId;
Expand Down Expand Up @@ -109,11 +114,16 @@ public Map<String, ParameterData> parameters() {
return parameters;
}

public String packageId() {
return packageId;
}

public enum Kind {
FUNCTION,
CONNECTOR,
REMOTE,
RESOURCE
RESOURCE,
LISTENER_INIT,
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ public static BuildProject getSampleProject() {
// Obtain the Ballerina distribution path
String ballerinaHome = System.getProperty(BALLERINA_HOME_PROPERTY);
if (ballerinaHome == null || ballerinaHome.isEmpty()) {
Path currentPath = getPath(Paths.get(
PackageUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath()));
Path distributionPath = getParentPath(getParentPath(getParentPath(currentPath)));
System.setProperty(BALLERINA_HOME_PROPERTY, distributionPath.toString());
// Path currentPath = getPath(Paths.get(
// PackageUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath()));
// Path distributionPath = getParentPath(getParentPath(getParentPath(currentPath)));
// System.setProperty(BALLERINA_HOME_PROPERTY, distributionPath.toString());
System.setProperty(BALLERINA_HOME_PROPERTY, "/Users/lakshanweerasinghe/.ballerina/ballerina-home/distributions/ballerina-2201.12.0");
}

try {
Expand All @@ -80,7 +81,7 @@ public static BuildProject getSampleProject() {
"org = \"wso2\"\n" +
"name = \"sample\"\n" +
"version = \"0.1.0\"\n" +
"distribution = \"2201.11.0\"";
"distribution = \"2201.12.0\"";
Files.writeString(ballerinaTomlFile, tomlContent, StandardOpenOption.CREATE);
return BuildProject.load(tempDir);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://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.modelgenerator.commons;

import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;

/**
* Manages database operations for retrieving information about external connectors and functions.
*
* @since 2.0.0
*/
public class ServiceDatabaseManager {

private static final String INDEX_FILE_NAME = "service-index.sqlite";
private static final Logger LOGGER = Logger.getLogger(ServiceDatabaseManager.class.getName());
private final String dbPath;

private static class Holder {
private static final ServiceDatabaseManager INSTANCE = new ServiceDatabaseManager();
}

public static ServiceDatabaseManager getInstance() {
return Holder.INSTANCE;
}

private ServiceDatabaseManager() {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Failed to load SQLite JDBC driver", e);
}

Path tempDir;
try {
tempDir = Files.createTempDirectory("service-index");
} catch (IOException e) {
throw new RuntimeException("Failed to create a temporary directory", e);
}

URL dbUrl = getClass().getClassLoader().getResource(INDEX_FILE_NAME);
if (dbUrl == null) {
throw new RuntimeException("Database resource not found: " + INDEX_FILE_NAME);
}
Path tempFile = tempDir.resolve(INDEX_FILE_NAME);
try {
Files.copy(dbUrl.openStream(), tempFile);
} catch (IOException e) {
throw new RuntimeException("Failed to copy the database file to the temporary directory", e);
}

dbPath = "jdbc:sqlite:" + tempFile.toString();
}

public Optional<FunctionData> getListener(String org, String module) {
StringBuilder sql = new StringBuilder("SELECT ");
sql.append("l.listener_id, ");
sql.append("l.name AS listener_name, ");
sql.append("l.description AS listener_description, ");
sql.append("l.return_error, ");
sql.append("p.package_id, ");
sql.append("p.name AS package_name, ");
sql.append("p.org, ");
sql.append("p.version ");
sql.append("FROM Listener l ");
sql.append("JOIN Package p ON l.package_id = p.package_id ");
sql.append("WHERE p.org = ? ");
sql.append("AND p.name = ? ");

try (Connection conn = DriverManager.getConnection(dbPath);
PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
stmt.setString(1, org);
stmt.setString(2, module);

ResultSet rs = stmt.executeQuery();
if (rs.next()) {
FunctionData functionData = new FunctionData(
rs.getInt("listener_id"),
rs.getString("listener_name"),
rs.getString("listener_description"),
null,
rs.getString("package_name"),
rs.getString("org"),
rs.getString("version"),
null,
null,
rs.getBoolean("return_error"),
false);
functionData.setPackageId(rs.getString("package_id"));
return Optional.of(functionData);
}
return Optional.empty();
} catch (SQLException e) {
Logger.getGlobal().severe("Error executing query: " + e.getMessage());
return Optional.empty();
}
}

public LinkedHashMap<String, ParameterData> getFunctionParametersAsMap(int listenerId) {
String sql = "SELECT " +
"p.parameter_id, " +
"p.name, " +
"p.type, " +
"p.kind, " +
"p.optional, " +
"p.default_value, " +
"p.description, " +
"p.import_statements, " +
"pmt.type AS member_type, " +
"pmt.kind AS member_kind, " +
"pmt.package AS member_package " +
"FROM Parameter p " +
"LEFT JOIN ParameterMemberType pmt ON p.parameter_id = pmt.parameter_id " +
"WHERE p.listener_id = ?;";

try (Connection conn = DriverManager.getConnection(dbPath);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, listenerId);
ResultSet rs = stmt.executeQuery();

// Use a builder to accumulate parameter data and member types
LinkedHashMap<String, ParameterDataBuilder> builders = new LinkedHashMap<>();

while (rs.next()) {
String paramName = rs.getString("name");
int parameterId = rs.getInt("parameter_id");
String type = rs.getString("type");
ParameterData.Kind kind = ParameterData.Kind.valueOf(rs.getString("kind"));
String defaultValue = rs.getString("default_value");
String description = rs.getString("description");
boolean optional = rs.getBoolean("optional");
String importStatements = rs.getString("import_statements");

// Member type data
String memberType = rs.getString("member_type");
String memberKind = rs.getString("member_kind");
String memberPackage = rs.getString("member_package");

// Get or create the builder for this parameter
ParameterDataBuilder builder = builders.get(paramName);
if (builder == null) {
builder = new ParameterDataBuilder();
builder.parameterId = parameterId;
builder.name = paramName;
builder.type = type;
builder.kind = kind;
builder.defaultValue = defaultValue;
builder.description = description;
builder.optional = optional;
builder.importStatements = importStatements;
builders.put(paramName, builder);
}

// Add member type if present
if (memberType != null) {
ParameterMemberTypeData memberData = new ParameterMemberTypeData(
memberType, memberKind, memberPackage);
builder.typeMembers.add(memberData);
}
}

// Convert builders to ParameterData
LinkedHashMap<String, ParameterData> parameterResults = new LinkedHashMap<>();
for (ParameterDataBuilder builder : builders.values()) {
parameterResults.put(builder.name, builder.build());
}
return parameterResults;

} catch (SQLException e) {
Logger.getGlobal().severe("Error executing query: " + e.getMessage());
return new LinkedHashMap<>();
}
}

// Helper builder class
private static class ParameterDataBuilder {
int parameterId;
String name;
String type;
ParameterData.Kind kind;
String defaultValue;
String description;
boolean optional;
String importStatements;
List<ParameterMemberTypeData> typeMembers = new ArrayList<>();

ParameterData build() {
return new ParameterData(
parameterId,
name,
type,
kind,
defaultValue,
description,
optional,
importStatements,
typeMembers
);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ dependencies {
exclude group: "javax.validation", module: "validation-api"
}
implementation "io.swagger.core.v3:swagger-models"
implementation "org.xerial:sqlite-jdbc:${sqliteJdbcVersion}"
}

def balDistribution = file("$project.buildDir/extracted-distribution/jballerina-tools-${ballerinaLangVersion}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
import io.ballerina.compiler.syntax.tree.SyntaxTree;
import io.ballerina.compiler.syntax.tree.TypeDefinitionNode;
import io.ballerina.compiler.syntax.tree.TypeDescriptorNode;
import io.ballerina.modelgenerator.commons.DatabaseManager;
import io.ballerina.modelgenerator.commons.FunctionData;
import io.ballerina.modelgenerator.commons.FunctionDataBuilder;
import io.ballerina.modelgenerator.commons.ModuleInfo;
import io.ballerina.modelgenerator.commons.ServiceDatabaseManager;
import io.ballerina.projects.Document;
import io.ballerina.projects.Module;
import io.ballerina.projects.ModuleId;
Expand Down Expand Up @@ -204,7 +209,7 @@ public CompletableFuture<ListenerDiscoveryResponse> getListeners(ListenerDiscove
public CompletableFuture<ListenerModelResponse> getListenerModel(ListenerModelRequest request) {
return CompletableFuture.supplyAsync(() -> {
try {
return getListenerByName(request.moduleName())
return ListenerUtil.getListenerByName(request)
.map(ListenerModelResponse::new)
.orElseGet(ListenerModelResponse::new);
} catch (Throwable e) {
Expand Down Expand Up @@ -619,7 +624,8 @@ public CompletableFuture<ListenerFromSourceResponse> getListenerFromSource(Commo
if (listenerName.isEmpty()) {
return new ListenerFromSourceResponse();
}
Optional<Listener> listener = getListenerByName(listenerName.get());
Optional<Listener> listener = ListenerUtil.getListenerByName(new
ListenerModelRequest("", "", ""));
if (listener.isEmpty()) {
return new ListenerFromSourceResponse();
}
Expand Down Expand Up @@ -1143,26 +1149,6 @@ private Optional<TriggerBasicInfo> getTriggerBasicInfoByName(String name) {
}
}

private Optional<Listener> getListenerByName(String name) {
if (!name.equals(ServiceModelGeneratorConstants.HTTP) &&
!name.equals(ServiceModelGeneratorConstants.GRAPHQL) &&
!name.equals(ServiceModelGeneratorConstants.TCP) &&
triggerProperties.values().stream().noneMatch(trigger -> trigger.name().equals(name))) {
return Optional.empty();
}
InputStream resourceStream = getClass().getClassLoader()
.getResourceAsStream(String.format("listeners/%s.json", name));
if (resourceStream == null) {
return Optional.empty();
}

try (JsonReader reader = new JsonReader(new InputStreamReader(resourceStream, StandardCharsets.UTF_8))) {
return Optional.of(new Gson().fromJson(reader, Listener.class));
} catch (IOException e) {
return Optional.empty();
}
}

private Optional<Service> getServiceByName(String name) {
if (!name.equals(ServiceModelGeneratorConstants.HTTP) &&
!name.equals(ServiceModelGeneratorConstants.GRAPHQL) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public class Codedata {
private boolean inDisplayAnnotation;
private String type;
private String argType;
private String originalName;

public Codedata() {
}

public Codedata(String type) {
this.type = type;
Expand Down Expand Up @@ -95,4 +99,12 @@ public String getArgType() {
public void setArgType(String argType) {
this.argType = argType;
}

public String getOriginalName() {
return originalName;
}

public void setOriginalName(String originalName) {
this.originalName = originalName;
}
}
Loading

0 comments on commit 26d7ae7

Please sign in to comment.