Skip to content

Commit

Permalink
Merge pull request #646 from LakshanWeerasinghe/service-index
Browse files Browse the repository at this point in the history
Introduce an index to service model generator module
  • Loading branch information
hasithaa authored Mar 5, 2025
2 parents ec7850f + e67ba89 commit 0709e3f
Show file tree
Hide file tree
Showing 30 changed files with 4,889 additions and 118 deletions.
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 @@ -80,7 +80,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,228 @@
/*
* 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 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.name = ? ");

try (Connection conn = DriverManager.getConnection(dbPath);
PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
stmt.setString(1, 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
Loading

0 comments on commit 0709e3f

Please sign in to comment.