Merge branch 'bug/datasource-api-validations' into 'release'

Postgres plugin load connection details from rich data structure instead of the URL

See merge request theappsmith/internal-tools-server!259
This commit is contained in:
Shrikant Kandula 2020-04-08 11:50:58 +00:00
commit d25b4acfd3

View File

@ -1,38 +1,39 @@
package com.external.plugins;
import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.external.models.ActionExecutionResult;
import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.*;
import com.appsmith.external.pluginExceptions.AppsmithPluginError;
import com.appsmith.external.pluginExceptions.AppsmithPluginException;
import com.appsmith.external.plugins.BasePlugin;
import com.appsmith.external.plugins.PluginExecutor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;
import org.pf4j.Extension;
import org.pf4j.PluginException;
import org.pf4j.PluginWrapper;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.sql.*;
import java.util.*;
import static com.appsmith.external.models.Connection.Mode.ReadOnly;
@Slf4j
public class PostgresPlugin extends BasePlugin {
private static ObjectMapper objectMapper;
private static ObjectMapper objectMapper = new ObjectMapper();
static String JDBC_DRIVER = "org.postgresql.Driver";
static final String JDBC_DRIVER = "org.postgresql.Driver";
private static final String USER = "user";
private static final String PASSWORD = "password";
private static final String SSL = "ssl";
public PostgresPlugin(PluginWrapper wrapper) {
super(wrapper);
this.objectMapper = new ObjectMapper();
}
/**
@ -47,58 +48,95 @@ public class PostgresPlugin extends BasePlugin {
public static class PostgresPluginExecutor implements PluginExecutor {
@Override
public Mono<Object> execute(Object connection,
public Mono<Object> execute(@NonNull Object connection,
DatasourceConfiguration datasourceConfiguration,
ActionConfiguration actionConfiguration) {
Connection conn = (Connection) connection;
Assert.notNull(conn);
ArrayList list = new ArrayList(50);
Map<String, Object> queryJson = actionConfiguration.getQuery();
String query = (String) queryJson.get("cmd");
if (query == null) {
return pluginErrorMono("Missing required parameter: Query.");
}
List<Map<String, Object>> rowsList = new ArrayList<>(50);
try {
Statement statement = conn.createStatement();
Map<String, Object> queryJson = actionConfiguration.getQuery();
String query = (String) queryJson.get("cmd");
ResultSet resultSet = statement.executeQuery(query);
ResultSetMetaData metaData = resultSet.getMetaData();
Integer colCount = metaData.getColumnCount();
int colCount = metaData.getColumnCount();
while (resultSet.next()) {
HashMap row = new HashMap(colCount);
Map<String, Object> row = new HashMap<>(colCount);
for (int i = 1; i <= colCount; i++) {
row.put(metaData.getColumnName(i), resultSet.getObject(i));
}
list.add(row);
rowsList.add(row);
}
} catch (SQLException e) {
log.error("", e);
return pluginErrorMono(e);
}
ActionExecutionResult result = new ActionExecutionResult();
result.setBody(objectMapper.valueToTree(list));
result.setBody(objectMapper.valueToTree(rowsList));
result.setShouldCacheResponse(true);
System.out.println("In the PostgresPlugin, got action execution result: " + result.toString());
return Mono.just(result);
}
private Mono<Object> pluginErrorMono(Object... args) {
return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, args));
}
@Override
public Object datasourceCreate(DatasourceConfiguration datasourceConfiguration) {
Connection conn = null;
try {
// Load the class into JVM
Class.forName(JDBC_DRIVER);
// Create the connection
conn = DriverManager.getConnection(datasourceConfiguration.getUrl(),
datasourceConfiguration.getAuthentication().getUsername(),
datasourceConfiguration.getAuthentication().getPassword());
return conn;
} catch (ClassNotFoundException e) {
log.error("", e);
} catch (SQLException e) {
log.error("", e);
return pluginErrorMono("Error loading Postgres JDBC Driver class.");
}
String url;
AuthenticationDTO authentication = datasourceConfiguration.getAuthentication();
Properties properties = new Properties();
properties.putAll(Map.of(
USER, authentication.getUsername(),
PASSWORD, authentication.getPassword(),
// TODO: Set SSL connection parameters.
SSL, datasourceConfiguration.getConnection().getSsl() != null
));
if (CollectionUtils.isEmpty(datasourceConfiguration.getEndpoints())) {
url = datasourceConfiguration.getUrl();
} else {
StringBuilder urlBuilder = new StringBuilder("jdbc:postgresql://");
for (Endpoint endpoint : datasourceConfiguration.getEndpoints()) {
urlBuilder
.append(endpoint.getHost())
.append(':')
.append(ObjectUtils.defaultIfNull(endpoint.getPort(), 5432L))
.append('/')
.append(authentication.getDatabaseName());
}
url = urlBuilder.toString();
}
try {
Connection connection = DriverManager.getConnection(url, properties);
connection.setReadOnly(ReadOnly.equals(datasourceConfiguration.getConnection().getMode()));
return connection;
} catch (SQLException e) {
return pluginErrorMono("Error connecting to Postgres.");
}
// Connection wasn't created. Return null
return null;
}
@Override
@ -109,17 +147,24 @@ public class PostgresPlugin extends BasePlugin {
conn.close();
}
} catch (SQLException e) {
log.error("", e);
try {
throw new PluginException(e);
} catch (PluginException ex) {
ex.printStackTrace();
}
log.error("Error closing Postgres Connection.", e);
}
}
@SuppressWarnings("RedundantIfStatement")
@Override
public Boolean isDatasourceValid(DatasourceConfiguration datasourceConfiguration) {
public Boolean isDatasourceValid(@NonNull DatasourceConfiguration datasourceConfiguration) {
if (CollectionUtils.isEmpty(datasourceConfiguration.getEndpoints())) {
return false;
}
if (datasourceConfiguration.getAuthentication() == null
|| datasourceConfiguration.getAuthentication().getUsername() == null
|| datasourceConfiguration.getAuthentication().getPassword() == null) {
return false;
}
return true;
}